@homecode/ui 4.16.0 → 4.17.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/dist/esm/index.js CHANGED
@@ -5,6 +5,7 @@ export { Calendar } from './src/components/Calendar/Calendar.js';
5
5
  export { Checkbox } from './src/components/Checkbox/Checkbox.js';
6
6
  export { Container } from './src/components/Container/Container.js';
7
7
  export { DatePicker } from './src/components/DatePicker/DatePicker.js';
8
+ export { DatePickerInput } from './src/components/DatePickerInput/DatePickerInput.js';
8
9
  export { DateTime, formatDate } from './src/components/DateTime/DateTime.js';
9
10
  export { Draggable } from './src/components/Draggable/Draggable.js';
10
11
  export { Expand } from './src/components/Expand/Expand.js';
@@ -44,6 +45,8 @@ export { env };
44
45
  export { config } from './src/tools/config.js';
45
46
  import * as array from './src/tools/array.js';
46
47
  export { array };
48
+ import * as date from './src/tools/date.js';
49
+ export { date };
47
50
  import * as string from './src/tools/string.js';
48
51
  export { string };
49
52
  import * as number from './src/tools/number.js';
@@ -50,7 +50,7 @@ function Calendar({ className, value, onDayPointerDown, onDayPointerUp, renderDa
50
50
  // @ts-ignore
51
51
  size: size, label: renderYearLabel?.(year) ?? 'Year', value: year,
52
52
  // @ts-ignore
53
- onChange: onYearChange, onBlur: onYearBlur }), jsx(Select, { className: S.month, size: size, label: renderMonthesLabel?.(month) ?? 'Month', options: monthOptions, value: month, onChange: val => setMonth(val) })] }), jsx("div", { className: S.weekDays, children: weekDaysArray.map((day, weekdayIndex) => (jsx("div", { className: cn(S.day, isWeekend(weekdayIndex) && weekendClassName), children: renderWeekDayLabel?.(day) ?? weekDays[day] }, `weekday-${day}`))) }), jsx("div", { className: S.days, children: daysArray.map((day, weekdayIndex) => {
53
+ onChange: onYearChange, onBlur: onYearBlur }), jsx(Select, { className: S.month, size: size, label: renderMonthesLabel?.(month) ?? 'Month', options: monthOptions, value: month, onChange: val => setMonth(val), required: true, hideRequiredStar: true })] }), jsx("div", { className: S.weekDays, children: weekDaysArray.map((day, weekdayIndex) => (jsx("div", { className: cn(S.day, isWeekend(weekdayIndex) && weekendClassName), children: renderWeekDayLabel?.(day) ?? weekDays[day] }, `weekday-${day}`))) }), jsx("div", { className: S.days, children: daysArray.map((day, weekdayIndex) => {
54
54
  const className = cn(S.day, day.currentMonth && S.currMonth, isWeekend(weekdayIndex) && weekendClassName, isSameDay(day, value) && S.selected);
55
55
  const dayProps = { className };
56
56
  if (onDayPointerDown) {
@@ -1,3 +1,14 @@
1
+ function dateToString(date) {
2
+ return `${date.year}-${date.month}-${date.day}`;
3
+ }
4
+ function strigToDate(dateString) {
5
+ const [year, month, day] = dateString.split('-');
6
+ return {
7
+ year: Number(year),
8
+ month: Number(month),
9
+ day: Number(day),
10
+ };
11
+ }
1
12
  function isDateEqual(date1, date2) {
2
13
  return (date1.year === date2.year &&
3
14
  date1.month === date2.month &&
@@ -17,4 +28,4 @@ function isDateBetween(date, startDate, endDate) {
17
28
  return isDateAfter(date, startDate) && isDateBefore(date, endDate);
18
29
  }
19
30
 
20
- export { isDateAfter, isDateBefore, isDateBetween, isDateEqual };
31
+ export { dateToString, isDateAfter, isDateBefore, isDateBetween, isDateEqual, strigToDate };
@@ -3,7 +3,7 @@ import { useState, useCallback, createElement } from 'react';
3
3
  import cn from 'classnames';
4
4
  import { Calendar } from '../Calendar/Calendar.js';
5
5
  import { Button } from '../Button/Button.js';
6
- import { isDateAfter, isDateBetween, isDateEqual } from './DatePicker.helpers.js';
6
+ import { dateToString, isDateAfter, strigToDate, isDateBetween, isDateEqual } from './DatePicker.helpers.js';
7
7
  import S from './DatePicker.styl.js';
8
8
 
9
9
  function DatePicker(props) {
@@ -11,32 +11,36 @@ function DatePicker(props) {
11
11
  const isRange = Array.isArray(value);
12
12
  const [isPicking, setIsPicking] = useState(false);
13
13
  const onFirstDateChange = useCallback((val) => {
14
- onChange(isRange ? [val, value[1]] : val);
14
+ const valStr = dateToString(val);
15
+ onChange(isRange ? [valStr, value[1]] : valStr);
15
16
  }, [value, onChange, isRange]);
16
17
  const onPointerDown = () => setIsPicking(true);
17
18
  const onPointerUp = () => setIsPicking(false);
18
19
  const renderDay = useCallback((val, { className, ...props }) => {
19
20
  const { day, year, month } = val;
21
+ const valStr = dateToString(val);
20
22
  if (isRange && isPicking) {
21
23
  props.onPointerOver = () => {
22
- const newVal = isDateAfter(value[0], val)
23
- ? [val, value[0]]
24
- : [value[0], val];
24
+ const newVal = isDateAfter(strigToDate(value[0]), val)
25
+ ? [valStr, value[0]]
26
+ : [value[0], valStr];
25
27
  onChange(newVal);
26
28
  };
27
29
  }
28
30
  const classes = [className, S.day];
29
31
  if (isRange) {
30
- if (isDateBetween(val, ...value))
32
+ const from = strigToDate(value[0]);
33
+ const to = strigToDate(value[1]);
34
+ if (isDateBetween(val, from, to))
31
35
  classes.push(S.between);
32
- if (isDateEqual(val, value[0]))
36
+ if (isDateEqual(val, from))
33
37
  classes.push(S.start);
34
- if (isDateEqual(val, value[1]))
38
+ if (isDateEqual(val, to))
35
39
  classes.push(S.end);
36
40
  }
37
41
  return (createElement(Button, { ...props, variant: "clear", className: cn(classes), size: size, key: `${year}-${month}-${day}` }, day));
38
42
  }, [size, isPicking, isRange, value, onChange]);
39
- return (jsxs("div", { className: cn(S.root, props.className), onPointerDown: onPointerDown, onPointerUp: onPointerUp, children: [jsx(Calendar, { size: size, hideOtherMonthDays: true, ...calendarProps, renderDay: renderDay, value: isRange ? value[0] : value, onDayPointerDown: onFirstDateChange }), isRange && (jsx(Calendar, { size: size, hideOtherMonthDays: true, ...calendarProps, renderDay: renderDay, value: value[1], onDayPointerDown: val => onChange([value[0], val]), onDayPointerUp: val => onChange([value[0], val]) }))] }));
43
+ return (jsxs("div", { className: cn(S.root, props.className), onPointerDown: onPointerDown, onPointerUp: onPointerUp, children: [jsx(Calendar, { size: size, hideOtherMonthDays: isRange, ...calendarProps, renderDay: renderDay, value: strigToDate(isRange ? value[0] : value), onDayPointerDown: onFirstDateChange, onDayPointerUp: undefined }), isRange && (jsx(Calendar, { size: size, hideOtherMonthDays: isRange, ...calendarProps, renderDay: renderDay, value: strigToDate(value[1]), onDayPointerDown: val => onChange([value[0], dateToString(val)]), onDayPointerUp: val => onChange([value[0], dateToString(val)]) }))] }));
40
44
  }
41
45
 
42
46
  export { DatePicker };
@@ -0,0 +1,18 @@
1
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
+ import cn from 'classnames';
3
+ import { strToDate } from '../../tools/date.js';
4
+ import { DateTime } from '../DateTime/DateTime.js';
5
+ import { DatePicker } from '../DatePicker/DatePicker.js';
6
+ import { Button } from '../Button/Button.js';
7
+ import { Popup } from '../Popup/Popup.js';
8
+ import S from './DatePickerInput.styl.js';
9
+
10
+ function DatePickerInput(props) {
11
+ const { value, variant = 'default', size = 'm', popupProps, displayFormat = 'MMM Do YYYY', } = props;
12
+ const isRange = Array.isArray(value);
13
+ return (jsx(Popup, { size: size, focusControl: true, direction: "bottom-right", ...popupProps, trigger: jsx(Button, { variant: variant, size: size, children: isRange ? (jsxs(Fragment, { children: [jsx(DateTime, { value: strToDate(value[0]), format: displayFormat }), ' - ', jsx(DateTime, { value: strToDate(value[1]), format: displayFormat })] })) : (jsx(DateTime, { value: strToDate(value), format: displayFormat })) }), contentProps: {
14
+ className: cn(S.popupContent, isRange && S.range, S[`size-${size}`]),
15
+ }, content: jsx(DatePicker, { ...props, className: S.content, calendarProps: { className: S.calendar } }) }));
16
+ }
17
+
18
+ export { DatePickerInput };
@@ -0,0 +1,7 @@
1
+ import styleInject from '../../../node_modules/style-inject/dist/style-inject.es.js';
2
+
3
+ var css_248z = ".DatePickerInput_popupContent__rcVHH{min-width:-moz-fit-content;min-width:fit-content}.DatePickerInput_content__yll-b{padding:.5em}.DatePickerInput_range__xWj9K .DatePickerInput_content__yll-b{display:flex;flex-direction:row;flex-wrap:nowrap;gap:1em}.DatePickerInput_range__xWj9K .DatePickerInput_calendar__vf0za{width:50%}.DatePickerInput_size-s__5t05o{border-radius:6px!important}.DatePickerInput_size-s__5t05o .DatePickerInput_content__yll-b{min-width:12em;padding:8px}.DatePickerInput_range__xWj9K.DatePickerInput_size-s__5t05o .DatePickerInput_content__yll-b{min-width:25em}.DatePickerInput_size-m__TTkHV{border-radius:9px!important}.DatePickerInput_size-m__TTkHV .DatePickerInput_content__yll-b{min-width:16em;padding:12px}.DatePickerInput_range__xWj9K.DatePickerInput_size-m__TTkHV .DatePickerInput_content__yll-b{min-width:33em}.DatePickerInput_size-l__-fWkE{border-radius:12px!important}.DatePickerInput_size-l__-fWkE .DatePickerInput_content__yll-b{min-width:20em;padding:14px}.DatePickerInput_range__xWj9K.DatePickerInput_size-l__-fWkE .DatePickerInput_content__yll-b{min-width:41em}";
4
+ var S = {"popupContent":"DatePickerInput_popupContent__rcVHH","content":"DatePickerInput_content__yll-b","range":"DatePickerInput_range__xWj9K","calendar":"DatePickerInput_calendar__vf0za","size-s":"DatePickerInput_size-s__5t05o","size-m":"DatePickerInput_size-m__TTkHV","size-l":"DatePickerInput_size-l__-fWkE"};
5
+ styleInject(css_248z);
6
+
7
+ export { S as default };
@@ -28,6 +28,7 @@ import '../Checkbox/Checkbox.styl.js';
28
28
  import '../Container/Container.styl.js';
29
29
  import '../DatePicker/DatePicker.styl.js';
30
30
  import 'moment';
31
+ import '../DatePickerInput/DatePickerInput.styl.js';
31
32
  import '../Draggable/Draggable.styl.js';
32
33
  import '../Expand/Expand.styl.js';
33
34
  import '../Form/Form.styl.js';
@@ -334,7 +335,7 @@ class Input extends Component {
334
335
  const classes = cn(S.root, isTextArea && S.isTextArea, S[`size-${size}`], S[`variant-${variant}`], isFocused && S.isFocused, error && S.hasError, hasClear && S.hasClear, disabled && S.isDisabled, className);
335
336
  return (
336
337
  // @ts-ignore
337
- jsxs("div", { className: classes, title: value, children: [jsxs("label", { className: S.main, children: [jsx("div", { className: S.border, suppressHydrationWarning: true, style: { clipPath: labelClipPath } }, "border"), this.renderAddon('left'), this.wrapControll(createElement(Control, { ...controlProps, className: cn(S.control, controlProps?.className), ref: this.inputRef, key: "control" })), isNumber && (jsxs("div", { className: S.numberArrows, children: [jsx(Button, { variant: "clear", onClick: () => this.onNumberWheel(1), children: jsx(Icon, { type: "chevronUp", size: size }) }), jsx(Button, { variant: "clear", onClick: () => this.onNumberWheel(-1), children: jsx(Icon, { type: "chevronDown", size: size }) })] })), isTextArea && controlProps.placeholder && (jsx("span", { className: S.placeholder, spellCheck: false, children: controlProps.placeholder })), jsx(Label, { className: S.label, size: size, isOnTop: isLabelOnTop, isError: Boolean(error), onClipPathChange: this.onLabelClipPathChange, children: label }, "label"), this.renderAddon('right'), required && jsx(RequiredStar, { size: size }, "required-star")] }, "main"), hasClear && !disabled && hasValue && (jsx(Button, { className: S.clearButton, variant: "clear", size: size, square: true, onClick: this.onClearPress, title: "", children: jsx(Icon, { className: S.clearIcon, size: size, type: "close" }) }, "clear")), !disabled && typeof error === 'string' && (jsx(AssistiveText, { variant: "danger", size: size, children: error }, "assistive-text"))] }));
338
+ jsxs("div", { className: classes, title: value, children: [jsxs("label", { className: S.main, children: [jsx("div", { className: S.border, suppressHydrationWarning: true, style: { clipPath: labelClipPath } }, "border"), this.renderAddon('left'), this.wrapControll(createElement(Control, { ...controlProps, className: cn(S.control, controlProps?.className), ref: this.inputRef, key: "control" })), isNumber && (jsxs("div", { className: S.numberArrows, children: [jsx(Button, { variant: "clear", onClick: () => this.onNumberWheel(1), tabIndex: -1, children: jsx(Icon, { type: "chevronUp", size: size }) }), jsx(Button, { variant: "clear", onClick: () => this.onNumberWheel(-1), tabIndex: -1, children: jsx(Icon, { type: "chevronDown", size: size }) })] })), isTextArea && controlProps.placeholder && (jsx("span", { className: S.placeholder, spellCheck: false, children: controlProps.placeholder })), jsx(Label, { className: S.label, size: size, isOnTop: isLabelOnTop, isError: Boolean(error), onClipPathChange: this.onLabelClipPathChange, children: label }, "label"), this.renderAddon('right'), required && jsx(RequiredStar, { size: size }, "required-star")] }, "main"), hasClear && !disabled && hasValue && (jsx(Button, { className: S.clearButton, variant: "clear", size: size, square: true, onClick: this.onClearPress, title: "", children: jsx(Icon, { className: S.clearIcon, size: size, type: "close" }) }, "clear")), !disabled && typeof error === 'string' && (jsx(AssistiveText, { variant: "danger", size: size, children: error }, "assistive-text"))] }));
338
339
  }
339
340
  }
340
341
 
@@ -31,6 +31,7 @@ import '../Checkbox/Checkbox.styl.js';
31
31
  import '../Container/Container.styl.js';
32
32
  import '../DatePicker/DatePicker.styl.js';
33
33
  import 'moment';
34
+ import '../DatePickerInput/DatePickerInput.styl.js';
34
35
  import { Draggable } from '../Draggable/Draggable.js';
35
36
  import '../Expand/Expand.styl.js';
36
37
  import '../Form/Form.styl.js';
@@ -242,7 +242,8 @@ class Popup extends Component {
242
242
  return;
243
243
  }
244
244
  // if scrolling outside this popup - close it
245
- if (!this.isPointerOver(e.target, S.content)) {
245
+ if (!this.isPointerOver(e.target, S.content) &&
246
+ !childs[this.id]?.length) {
246
247
  this.needDropOffset = true;
247
248
  this.close();
248
249
  }
@@ -280,7 +281,7 @@ class Popup extends Component {
280
281
  this.focused = false;
281
282
  this.props.triggerProps?.onBlur?.(e);
282
283
  // give time to fire clicks inside popup
283
- this.timers.after(80, () => {
284
+ this.timers.after(60, () => {
284
285
  if (!this.isLastClickInside())
285
286
  this.close();
286
287
  });
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Convert ISO 8601 format ("YYYY-MM-DD") to Date object
3
+ * @param str
4
+ * @returns Date
5
+ */
6
+ const strToDate = (str) => {
7
+ const [year, month, day] = str.split('-').map(Number);
8
+ return new Date(year, month - 1, day);
9
+ };
10
+
11
+ export { strToDate };
@@ -5,14 +5,14 @@ export type Day = Date & {
5
5
  };
6
6
  export type DayProps = {
7
7
  className: string;
8
- onPointerDown: () => void;
9
- onPointerUp: () => void;
8
+ onPointerDown?: () => void;
9
+ onPointerUp?: () => void;
10
10
  };
11
11
  export type Props = {
12
12
  className?: string;
13
13
  value: Date;
14
- onDayPointerDown: (value: Date) => void;
15
- onDayPointerUp: (value: Date) => void;
14
+ onDayPointerDown?: (value: Date) => void;
15
+ onDayPointerUp?: (value: Date) => void;
16
16
  startOfWeek?: number;
17
17
  size?: Size;
18
18
  renderDay?: (day: Day, dayProps: DayProps) => ReactNode;
@@ -1,4 +1,10 @@
1
1
  import type { Date } from 'uilib/types';
2
+ export declare function dateToString(date: Date): string;
3
+ export declare function strigToDate(dateString: string): {
4
+ year: number;
5
+ month: number;
6
+ day: number;
7
+ };
2
8
  export declare function isDateEqual(date1: Date, date2: Date): boolean;
3
9
  export declare function isDateBefore(date1: Date, date2: Date): boolean;
4
10
  export declare function isDateAfter(date1: Date, date2: Date): boolean;
@@ -1,10 +1,10 @@
1
- import type { Size, Date } from 'uilib/types';
1
+ import type { Size } from 'uilib/types';
2
2
  import type { Props as CalendarProps } from 'uilib/components/Calendar/Calendar.types';
3
- export type Value = Date | [Date, Date];
3
+ export type Value = string | [string, string];
4
4
  export type Props = {
5
5
  className?: string;
6
6
  value: Value;
7
7
  onChange: (value: Value) => void;
8
8
  size?: Size;
9
- calendarProps?: CalendarProps;
9
+ calendarProps?: Partial<CalendarProps>;
10
10
  };
@@ -0,0 +1,3 @@
1
+ /// <reference types="react" />
2
+ import * as T from './DatePickerInput.types';
3
+ export declare function DatePickerInput(props: T.Props): JSX.Element;
@@ -0,0 +1,12 @@
1
+ import type { Size, Variant } from 'uilib/types';
2
+ import type { Props as PopupProps } from 'uilib/components/Popup/Popup.types';
3
+ export type Value = string | [string, string];
4
+ export type Props = {
5
+ className?: string;
6
+ size?: Size;
7
+ displayFormat?: string;
8
+ value: Value;
9
+ onChange: (value: Value) => void;
10
+ variant?: Variant;
11
+ popupProps?: PopupProps;
12
+ };
@@ -1,3 +1,2 @@
1
- /// <reference types="react" />
2
1
  declare const _default: () => JSX.Element;
3
2
  export default _default;
@@ -5,6 +5,7 @@ export * from './Calendar/Calendar';
5
5
  export * from './Checkbox/Checkbox';
6
6
  export * from './Container/Container';
7
7
  export * from './DatePicker/DatePicker';
8
+ export * from './DatePickerInput/DatePickerInput';
8
9
  export * from './DateTime/DateTime';
9
10
  export * from './Draggable/Draggable';
10
11
  export * from './Expand/Expand';
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Convert ISO 8601 format ("YYYY-MM-DD") to Date object
3
+ * @param str
4
+ * @returns Date
5
+ */
6
+ export declare const strToDate: (str: string) => Date;
@@ -1,6 +1,7 @@
1
1
  export * as env from './env';
2
2
  export { config } from './config';
3
3
  export * as array from './array';
4
+ export * as date from './date';
4
5
  export * as string from './string';
5
6
  export * as number from './number';
6
7
  export * as object from './object';
@@ -19,3 +19,4 @@ export type Date = {
19
19
  day?: number;
20
20
  ISO?: string;
21
21
  };
22
+ export type Variant = 'default' | 'outlined';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@homecode/ui",
3
- "version": "4.16.0",
3
+ "version": "4.17.1",
4
4
  "description": "React UI components library",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1",