@laser-ui/components 1.1.0 → 1.2.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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,22 @@
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
+ # [1.2.0](https://github.com/laser-ui/laser-ui/compare/v1.1.1...v1.2.0) (2024-09-12)
6
+
7
+ ### Features
8
+
9
+ - **components:** form support `labelWrap` ([ffeb41a](https://github.com/laser-ui/laser-ui/commit/ffeb41afb4531e33b53343f245190dfa34872188))
10
+
11
+ ### Performance Improvements
12
+
13
+ - **components:** optimize `Validators.required` ([39f452c](https://github.com/laser-ui/laser-ui/commit/39f452ce964b28fe3271c0016290a8a7667cdcf0))
14
+
15
+ ## [1.1.1](https://github.com/laser-ui/laser-ui/compare/v1.1.0...v1.1.1) (2024-08-30)
16
+
17
+ ### Bug Fixes
18
+
19
+ - fix automatically update when nested ([d1c0b46](https://github.com/laser-ui/laser-ui/commit/d1c0b4645965e31b382058b60b2569b253c162e5))
20
+
5
21
  # [1.1.0](https://github.com/laser-ui/laser-ui/compare/v1.0.2...v1.1.0) (2024-08-30)
6
22
 
7
23
  ### Features
@@ -9,7 +9,7 @@ import { DropdownItem as DropdownItemFC } from './internal/DropdownItem';
9
9
  import { DropdownSub } from './internal/DropdownSub';
10
10
  import { checkEnableItem, getSameLevelEnableItems } from './utils';
11
11
  import { CLASSES } from './vars';
12
- import { useComponentProps, useControlled, useFocusVisible, useJSS, useMaxIndex, useNamespace, useNestedPopup, useStyled, useTranslation, } from '../hooks';
12
+ import { useComponentProps, useContainerScrolling, useControlled, useFocusVisible, useJSS, useMaxIndex, useNamespace, useNestedPopup, useStyled, useTranslation, } from '../hooks';
13
13
  import { Popup } from '../internal/popup';
14
14
  import { Portal } from '../internal/portal';
15
15
  import { Transition } from '../internal/transition';
@@ -254,14 +254,14 @@ function DropdownFC(props, ref) {
254
254
  });
255
255
  return getNodes(list, 0, []);
256
256
  })();
257
- useImperativeHandle(ref, () => ({
258
- updatePosition: () => {
259
- updatePosition();
260
- for (const fn of dataRef.current.updatePosition.values()) {
261
- fn();
262
- }
263
- },
264
- }), [updatePosition]);
257
+ const updateAllPosition = useEventCallback(() => {
258
+ updatePosition();
259
+ for (const fn of dataRef.current.updatePosition.values()) {
260
+ fn();
261
+ }
262
+ });
263
+ useContainerScrolling(triggerRef, updateAllPosition, !visible);
264
+ useImperativeHandle(ref, () => ({ updatePosition: updateAllPosition }), [updateAllPosition]);
265
265
  return (_jsx(Popup, { visible: visible, trigger: trigger, updatePosition: {
266
266
  fn: updatePosition,
267
267
  triggerRef,
@@ -20,7 +20,7 @@ export const DropdownSub = forwardRef((props, ref) => {
20
20
  const visible = !isUndefined(popupState);
21
21
  const transformOrigin = useRef();
22
22
  const updatePosition = useEventCallback(() => {
23
- if (visible && popupRef.current && triggerRef.current) {
23
+ if (!disabled && visible && popupRef.current && triggerRef.current) {
24
24
  const [width, height] = [popupRef.current.offsetWidth, popupRef.current.offsetHeight];
25
25
  const position = getHorizontalSidePosition(triggerRef.current, { width, height }, {
26
26
  placement: 'right',
@@ -42,6 +42,7 @@ export const DropdownSub = forwardRef((props, ref) => {
42
42
  fn: updatePosition,
43
43
  triggerRef,
44
44
  popupRef,
45
+ scroll: false,
45
46
  }, onVisibleChange: onVisibleChange, children: ({ renderTrigger, renderPopup }) => (_jsxs(_Fragment, { children: [renderTrigger(_jsxs("li", Object.assign({}, mergeCS(styled('dropdown__item', 'dropdown__item--sub', {
46
47
  'dropdown__item.is-expand': visible,
47
48
  'dropdown__item.is-disabled': disabled,
package/form/Form.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { __rest } from "tslib";
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { isUndefined } from 'lodash';
3
4
  import { useEffect, useRef } from 'react';
4
5
  import { FormItem } from './FormItem';
5
6
  import { CLASSES, FormContext } from './vars';
@@ -7,7 +8,7 @@ import { ConfigProvider } from '../config-provider';
7
8
  import { useComponentProps, useScopedProps, useStyled } from '../hooks';
8
9
  import { mergeCS } from '../utils';
9
10
  export const Form = (props) => {
10
- const _a = useComponentProps('Form', props), { children, styleOverrides, styleProvider, vertical = false, labelWidth, labelColon, requiredType = 'required', feedbackIcon = false, size: sizeProp } = _a, restProps = __rest(_a, ["children", "styleOverrides", "styleProvider", "vertical", "labelWidth", "labelColon", "requiredType", "feedbackIcon", "size"]);
11
+ const _a = useComponentProps('Form', props), { children, styleOverrides, styleProvider, vertical = false, labelWidth, labelWrap = false, labelColon, requiredType = 'required', feedbackIcon = false, size: sizeProp } = _a, restProps = __rest(_a, ["children", "styleOverrides", "styleProvider", "vertical", "labelWidth", "labelWrap", "labelColon", "requiredType", "feedbackIcon", "size"]);
11
12
  const styled = useStyled(CLASSES, { form: styleProvider === null || styleProvider === void 0 ? void 0 : styleProvider.form }, styleOverrides);
12
13
  const formRef = useRef(null);
13
14
  const { size } = useScopedProps({ size: sizeProp });
@@ -35,6 +36,7 @@ export const Form = (props) => {
35
36
  }, children: _jsx(ConfigProvider, { context: { componentSize: size }, children: _jsx(FormContext.Provider, { value: {
36
37
  vertical,
37
38
  labelWidth: labelWidth !== null && labelWidth !== void 0 ? labelWidth : (vertical ? undefined : 'auto'),
39
+ labelWrap: isUndefined(labelWidth) ? false : labelWrap,
38
40
  labelColon: labelColon !== null && labelColon !== void 0 ? labelColon : !vertical,
39
41
  requiredType,
40
42
  feedbackIcon,
package/form/FormItem.js CHANGED
@@ -4,7 +4,7 @@ import CancelFilled from '@material-design-icons/svg/filled/cancel.svg?react';
4
4
  import CheckCircleFilled from '@material-design-icons/svg/filled/check_circle.svg?react';
5
5
  import ErrorFilled from '@material-design-icons/svg/filled/error.svg?react';
6
6
  import HelpOutlineOutlined from '@material-design-icons/svg/outlined/help_outline.svg?react';
7
- import { isBoolean, isFunction, isNull, isNumber, isString } from 'lodash';
7
+ import { isBoolean, isFunction, isNull, isNumber, isString, isUndefined } from 'lodash';
8
8
  import { useContext, useId, useRef } from 'react';
9
9
  import { FormError } from './internal/FormError';
10
10
  import { Validators } from './model/validators';
@@ -22,7 +22,7 @@ const ValidateState = {
22
22
  Pending: 4,
23
23
  };
24
24
  export function FormItem(props) {
25
- const _a = useComponentProps('FormItem', props), { children, styleOverrides, styleProvider, formControls, label, labelWidth: labelWidthProp, labelExtra: labelExtraProp, labelFor, required: requiredProp } = _a, restProps = __rest(_a, ["children", "styleOverrides", "styleProvider", "formControls", "label", "labelWidth", "labelExtra", "labelFor", "required"]);
25
+ const _a = useComponentProps('FormItem', props), { children, styleOverrides, styleProvider, formControls, label, labelWidth: labelWidthProp, labelWrap: labelWrapProp, labelExtra: labelExtraProp, labelFor, required: requiredProp } = _a, restProps = __rest(_a, ["children", "styleOverrides", "styleProvider", "formControls", "label", "labelWidth", "labelWrap", "labelExtra", "labelFor", "required"]);
26
26
  const styled = useStyled(CLASSES, { form: styleProvider === null || styleProvider === void 0 ? void 0 : styleProvider.form }, styleOverrides);
27
27
  const { t } = useTranslation();
28
28
  const formContext = useContext(FormContext);
@@ -31,6 +31,7 @@ export function FormItem(props) {
31
31
  const uniqueId = useId();
32
32
  const getErrorId = (controlName) => `${controlName}-error-${uniqueId}`;
33
33
  const labelWidth = labelWidthProp !== null && labelWidthProp !== void 0 ? labelWidthProp : formContext.labelWidth;
34
+ const labelWrap = isUndefined(labelWidth) ? false : (labelWrapProp !== null && labelWrapProp !== void 0 ? labelWrapProp : formContext.labelWrap);
34
35
  const formControlProviders = (() => {
35
36
  const obj = {};
36
37
  Object.keys(formControls !== null && formControls !== void 0 ? formControls : {}).forEach((controlName) => {
@@ -149,9 +150,9 @@ export function FormItem(props) {
149
150
  className: restProps.className,
150
151
  style: restProps.style,
151
152
  }), { ref: divRef, children: _jsxs("div", Object.assign({}, styled('form__item-container'), { children: [labelWidth !== 0 && (_jsx("div", Object.assign({}, mergeCS(styled('form__item-label-wrapper'), {
152
- style: { width: formContext.vertical ? '100%' : labelWidth === 'auto' ? 'var(--label-width)' : labelWidth },
153
+ style: { width: formContext.vertical ? undefined : labelWidth === 'auto' ? 'var(--label-width)' : labelWidth },
153
154
  }), { children: label && (_jsxs("label", Object.assign({}, styled('form__item-label', {
154
- 'form__item-label--auto': !formContext.vertical && labelWidth === 'auto',
155
+ 'form__item-label--wrap': labelWrap,
155
156
  'form__item-label--required': formContext.requiredType === 'required' && required,
156
157
  'form__item-label--colon': formContext.labelColon,
157
158
  }), { htmlFor: labelFor, "data-l-form-label": true, children: [label, (labelExtra || (formContext.requiredType === 'optional' && !required)) && (_jsxs("div", Object.assign({}, styled('form__item-label-extra'), { children: [formContext.requiredType === 'optional' && !required && _jsx("span", { children: t('Form', 'Optional') }), labelExtra] })))] }))) }))), _jsxs("div", Object.assign({}, mergeCS(styled('form__item-content'), {
@@ -1,4 +1,4 @@
1
- import { isArray, isNull, isNumber, isString } from 'lodash';
1
+ import { isArray, isNumber, isString } from 'lodash';
2
2
  export class Validators {
3
3
  static min(min) {
4
4
  return (control) => {
@@ -29,7 +29,7 @@ export class Validators {
29
29
  };
30
30
  }
31
31
  static required(control) {
32
- const isEmpty = isArray(control.value) || isString(control.value) ? control.value.length === 0 : isNull(control.value) ? true : false;
32
+ const isEmpty = control.value == null || ((isArray(control.value) || isString(control.value)) && control.value.length === 0);
33
33
  return isEmpty ? { required: true } : null;
34
34
  }
35
35
  static email(control) {
package/form/types.d.ts CHANGED
@@ -23,6 +23,7 @@ export interface FormControlProvider {
23
23
  export interface FormContextData {
24
24
  vertical: boolean;
25
25
  labelWidth: number | string | undefined;
26
+ labelWrap: boolean;
26
27
  labelColon: boolean;
27
28
  requiredType: 'required' | 'optional' | 'hidden';
28
29
  feedbackIcon: boolean | {
@@ -35,6 +36,7 @@ export interface FormContextData {
35
36
  export interface FormProps extends BaseProps<'form', typeof CLASSES>, React.FormHTMLAttributes<HTMLFormElement> {
36
37
  vertical?: boolean;
37
38
  labelWidth?: number | string;
39
+ labelWrap?: boolean;
38
40
  labelColon?: boolean;
39
41
  requiredType?: 'required' | 'optional' | 'hidden';
40
42
  feedbackIcon?: boolean | {
@@ -54,6 +56,7 @@ export interface FormItemProps<T extends {
54
56
  formControls?: T;
55
57
  label?: React.ReactNode;
56
58
  labelWidth?: number | string;
59
+ labelWrap?: boolean;
57
60
  labelExtra?: {
58
61
  title: string;
59
62
  icon?: React.ReactElement;
package/form/vars.d.ts CHANGED
@@ -11,7 +11,7 @@ export declare const CLASSES: {
11
11
  'form__item-container': string;
12
12
  'form__item-label-wrapper': string;
13
13
  'form__item-label': string;
14
- 'form__item-label--auto': string;
14
+ 'form__item-label--wrap': string;
15
15
  'form__item-label--required': string;
16
16
  'form__item-label--colon': string;
17
17
  'form__item-label-extra': string;
package/form/vars.js CHANGED
@@ -9,7 +9,7 @@ export const CLASSES = {
9
9
  'form__item-container': '^form__item-container',
10
10
  'form__item-label-wrapper': '^form__item-label-wrapper',
11
11
  'form__item-label': '^form__item-label',
12
- 'form__item-label--auto': '^form__item-label--auto',
12
+ 'form__item-label--wrap': '^form__item-label--wrap',
13
13
  'form__item-label--required': '^form__item-label--required',
14
14
  'form__item-label--colon': '^form__item-label--colon',
15
15
  'form__item-label-extra': '^form__item-label-extra',
@@ -42,7 +42,7 @@ export function Popup(props) {
42
42
  changeVisible();
43
43
  }
44
44
  };
45
- useContainerScrolling(updatePosition.triggerRef, updatePosition.fn, disabled || !visibleProp);
45
+ useContainerScrolling(updatePosition.triggerRef, updatePosition.fn, disabled || updatePosition.scroll === false || !visibleProp);
46
46
  useResize(updatePosition.triggerRef, updatePosition.fn, undefined, disabled || !visibleProp);
47
47
  useResize(updatePosition.popupRef, updatePosition.fn, undefined, disabled || !visibleProp);
48
48
  useResize(contentResizeRef, updatePosition.fn, undefined, disabled || !visibleProp);
@@ -15,6 +15,7 @@ export interface PopupProps {
15
15
  fn: () => void;
16
16
  triggerRef: React.RefObject<HTMLElement>;
17
17
  popupRef: React.RefObject<HTMLElement>;
18
+ scroll?: boolean;
18
19
  };
19
20
  onVisibleChange: (visible: boolean) => void;
20
21
  }
package/menu/Menu.js CHANGED
@@ -2,13 +2,13 @@ import { __rest } from "tslib";
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import { findNested } from '@laser-ui/utils';
4
4
  import { isNull, isUndefined, nth } from 'lodash';
5
- import { Fragment, forwardRef, useId, useImperativeHandle, useRef, useState } from 'react';
5
+ import { Fragment, forwardRef, useCallback, useId, useImperativeHandle, useRef, useState } from 'react';
6
6
  import { MenuGroup } from './internal/MenuGroup';
7
7
  import { MenuItem as MenuItemFC } from './internal/MenuItem';
8
8
  import { MenuSub } from './internal/MenuSub';
9
9
  import { checkEnableItem, getSameLevelEnableItems } from './utils';
10
10
  import { CLASSES } from './vars';
11
- import { useComponentProps, useControlled, useFocusVisible, useNamespace, useNestedPopup, useStyled } from '../hooks';
11
+ import { useComponentProps, useContainerScrolling, useControlled, useFocusVisible, useNamespace, useNestedPopup, useStyled, } from '../hooks';
12
12
  import { CollapseTransition } from '../internal/transition';
13
13
  import { mergeCS } from '../utils';
14
14
  import { TTANSITION_DURING_BASE } from '../vars';
@@ -18,6 +18,7 @@ function MenuFC(props, ref) {
18
18
  const styled = useStyled(CLASSES, { menu: styleProvider === null || styleProvider === void 0 ? void 0 : styleProvider.menu, 'menu-popup': styleProvider === null || styleProvider === void 0 ? void 0 : styleProvider['menu-popup'] }, styleOverrides);
19
19
  const uniqueId = useId();
20
20
  const getItemId = (id) => `${namespace}-menu-item-${id}-${uniqueId}`;
21
+ const menuRef = useRef(null);
21
22
  const dataRef = useRef({
22
23
  mousedown: false,
23
24
  updatePosition: new Map(),
@@ -324,13 +325,13 @@ function MenuFC(props, ref) {
324
325
  };
325
326
  return getNodes(list, 0, [], true);
326
327
  })();
327
- useImperativeHandle(ref, () => ({
328
- updatePosition: () => {
329
- for (const fn of dataRef.current.updatePosition.values()) {
330
- fn();
331
- }
332
- },
333
- }), []);
328
+ const updatePosition = useCallback(() => {
329
+ for (const fn of dataRef.current.updatePosition.values()) {
330
+ fn();
331
+ }
332
+ }, []);
333
+ useContainerScrolling(menuRef, updatePosition);
334
+ useImperativeHandle(ref, () => ({ updatePosition }), [updatePosition]);
334
335
  return (_jsx(CollapseTransition, { originalSize: {
335
336
  width,
336
337
  }, collapsedSize: {
@@ -342,7 +343,7 @@ function MenuFC(props, ref) {
342
343
  leaving: {
343
344
  transition: ['width', 'padding', 'margin'].map((attr) => `${attr} ${TTANSITION_DURING_BASE}ms linear`).join(', '),
344
345
  },
345
- }, children: (menuRef, collapseStyle) => {
346
+ }, children: (collapseRef, collapseStyle) => {
346
347
  var _a;
347
348
  const preventBlur = (e) => {
348
349
  if (document.activeElement === e.currentTarget && e.button === 0) {
@@ -354,7 +355,10 @@ function MenuFC(props, ref) {
354
355
  _jsx("nav", Object.assign({}, restProps, mergeCS(styled('menu', { 'menu--horizontal': mode === 'horizontal' }), {
355
356
  className: restProps.className,
356
357
  style: Object.assign(Object.assign(Object.assign({}, restProps.style), { width }), collapseStyle),
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) => {
358
+ }), { ref: (el) => {
359
+ collapseRef.current = el;
360
+ menuRef.current = el;
361
+ }, 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) => {
358
362
  var _a;
359
363
  (_a = restProps.onFocus) === null || _a === void 0 ? void 0 : _a.call(restProps, e);
360
364
  if (!dataRef.current.mousedown) {
@@ -21,7 +21,7 @@ export const MenuSub = forwardRef((props, ref) => {
21
21
  const iconMode = mode === 'icon' && inNav;
22
22
  const transformOrigin = useRef();
23
23
  const updatePosition = useEventCallback(() => {
24
- if (visible && popupRef.current && triggerRef.current) {
24
+ if (!(disabled || mode === 'vertical') && visible && popupRef.current && triggerRef.current) {
25
25
  const height = popupRef.current.offsetHeight;
26
26
  let width = popupRef.current.offsetWidth;
27
27
  if (inHorizontalNav) {
@@ -56,6 +56,7 @@ export const MenuSub = forwardRef((props, ref) => {
56
56
  fn: updatePosition,
57
57
  triggerRef,
58
58
  popupRef,
59
+ scroll: false,
59
60
  }, onVisibleChange: onVisibleChange, children: ({ renderTrigger, renderPopup }) => (_jsxs(_Fragment, { children: [renderTrigger(_jsxs("li", Object.assign({}, mergeCS(styled('menu__item', 'menu__item--sub', {
60
61
  'menu__item--horizontal': inHorizontalNav,
61
62
  'menu__item--icon': iconMode,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@laser-ui/components",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "React components.",
5
5
  "keywords": [
6
6
  "ui",
@@ -40,5 +40,5 @@
40
40
  "access": "public",
41
41
  "directory": "../../dist/libs/components"
42
42
  },
43
- "gitHead": "6a7e6e2e141237b816d4a9f414bcf4c5274e14e6"
43
+ "gitHead": "b972aaf248e60ba8e9c9d5e09e07ab46116f4ad8"
44
44
  }