@veracity/vui 5.3.1-alpha.422947.2608191243 → 5.3.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/calendar/calendar.js +60 -54
- package/dist/calendar/calendar.js.map +1 -1
- package/dist/calendar/components/calendarHeader.js +2 -1
- package/dist/calendar/components/calendarHeader.js.map +1 -1
- package/dist/calendar/components/monthPicker.js +1 -1
- package/dist/calendar/components/monthPicker.js.map +1 -1
- package/dist/svg/helpers.js +12 -3
- package/dist/svg/helpers.js.map +1 -1
- package/package.json +1 -1
|
@@ -9,7 +9,7 @@ import { MonthPicker } from "./components/monthPicker.js";
|
|
|
9
9
|
import { YearPicker } from "./components/yearPicker.js";
|
|
10
10
|
import { useCalendar } from "./hooks/useCalendar.js";
|
|
11
11
|
import { useDefaultViewMonth } from "./hooks/useDefaultViewMonth.js";
|
|
12
|
-
import { useEffect, useRef, useState } from "react";
|
|
12
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
13
13
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
14
14
|
|
|
15
15
|
//#region src/calendar/calendar.tsx
|
|
@@ -18,14 +18,6 @@ const Calendar = vui((props, ref) => {
|
|
|
18
18
|
const { boundaries, className, fixedNumberOfWeeks = false, disabled, isStartDate, mode, onSelectDates, selectedDates, ...rest } = omitThemingProps(props);
|
|
19
19
|
const styles = useStyleConfig("Calendar", props);
|
|
20
20
|
const currentDateRef = useRef(isFrom(mode) || isExact(mode) ? selectedDates?.startDate : selectedDates?.endDate);
|
|
21
|
-
/**
|
|
22
|
-
* Effect to reset viewDate when selectedDates changes (onReset)
|
|
23
|
-
*/
|
|
24
|
-
useEffect(() => {
|
|
25
|
-
currentDateRef.current = isFrom(mode) || isExact(mode) ? selectedDates?.startDate : selectedDates?.endDate;
|
|
26
|
-
currentDateRef.current && setViewDate(currentDateRef.current);
|
|
27
|
-
}, [selectedDates]);
|
|
28
|
-
const calendarRef = useRef(null);
|
|
29
21
|
const defaultViewMonth = useDefaultViewMonth({
|
|
30
22
|
boundaries,
|
|
31
23
|
selectedDate: currentDateRef.current,
|
|
@@ -33,57 +25,71 @@ const Calendar = vui((props, ref) => {
|
|
|
33
25
|
});
|
|
34
26
|
const [timeUnitMode, setTimeUnitMode] = useState("day");
|
|
35
27
|
const [viewDate, setViewDate] = useState(defaultViewMonth);
|
|
28
|
+
const calendar = useCalendar({
|
|
29
|
+
boundaries,
|
|
30
|
+
mode,
|
|
31
|
+
selectedDates,
|
|
32
|
+
timeUnitMode,
|
|
33
|
+
viewDate,
|
|
34
|
+
fixedNumberOfWeeks
|
|
35
|
+
});
|
|
36
36
|
/**
|
|
37
|
-
*
|
|
38
|
-
|
|
39
|
-
const onChangeViewItem = (direction) => {
|
|
40
|
-
const newViewMonth = processViewDate(viewDate, direction, timeUnitMode, calendarRef?.current?.items);
|
|
41
|
-
newViewMonth && setViewDate(newViewMonth);
|
|
42
|
-
};
|
|
43
|
-
/**
|
|
44
|
-
* Handles clicking on a day
|
|
37
|
+
* Effect to reset viewDate when selectedDates changes (onReset)
|
|
38
|
+
* Compare timestamps to avoid resetting the view when the object reference changes but the date value hasn't.
|
|
45
39
|
*/
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
const newDate = isFrom(mode) || isExact(mode) ? selectedDates?.startDate : selectedDates?.endDate;
|
|
42
|
+
if (newDate?.getTime() !== currentDateRef.current?.getTime()) {
|
|
43
|
+
currentDateRef.current = newDate;
|
|
44
|
+
if (newDate) setViewDate(newDate);
|
|
45
|
+
}
|
|
46
|
+
}, [selectedDates, mode]);
|
|
50
47
|
/**
|
|
51
|
-
*
|
|
48
|
+
* Send update date to parent component
|
|
52
49
|
*/
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
50
|
+
const updateDateState = useCallback((newDate) => {
|
|
51
|
+
const dateRange = { ...selectedDates };
|
|
52
|
+
if (isTo(mode)) dateRange.endDate = newDate;
|
|
53
|
+
else dateRange.startDate = newDate;
|
|
54
|
+
if (newDate && !disabled) onSelectDates?.(dateRange);
|
|
55
|
+
}, [
|
|
56
|
+
selectedDates,
|
|
57
|
+
mode,
|
|
58
|
+
disabled,
|
|
59
|
+
onSelectDates
|
|
60
|
+
]);
|
|
59
61
|
/**
|
|
60
|
-
* Handles clicking
|
|
62
|
+
* Handles clicking next/prev in header
|
|
61
63
|
*/
|
|
62
|
-
const
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
64
|
+
const onChangeViewItem = useCallback((direction) => {
|
|
65
|
+
const newViewMonth = processViewDate(viewDate, direction, timeUnitMode, calendar.items);
|
|
66
|
+
if (newViewMonth) setViewDate(newViewMonth);
|
|
67
|
+
}, [
|
|
68
|
+
viewDate,
|
|
69
|
+
timeUnitMode,
|
|
70
|
+
calendar.items
|
|
71
|
+
]);
|
|
68
72
|
/**
|
|
69
|
-
*
|
|
73
|
+
* Handles clicking on a day, month or year cell. The active timeUnitMode decides
|
|
74
|
+
* how the clicked date is processed and which unit to drill down into next.
|
|
70
75
|
*/
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
if (
|
|
74
|
-
|
|
75
|
-
|
|
76
|
+
const onSelect = useCallback((clickedDate) => () => {
|
|
77
|
+
let processedDate = clickedDate;
|
|
78
|
+
if (isMonth(timeUnitMode)) {
|
|
79
|
+
processedDate = processSelectMonth(clickedDate, mode, boundaries);
|
|
80
|
+
setTimeUnitMode("day");
|
|
81
|
+
} else if (isYear(timeUnitMode)) {
|
|
82
|
+
processedDate = processSelectYear(clickedDate, mode, boundaries);
|
|
83
|
+
setTimeUnitMode("month");
|
|
76
84
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
boundaries,
|
|
81
|
-
mode,
|
|
82
|
-
selectedDates,
|
|
85
|
+
updateDateState(processedDate);
|
|
86
|
+
setViewDate(processedDate);
|
|
87
|
+
}, [
|
|
83
88
|
timeUnitMode,
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
89
|
+
mode,
|
|
90
|
+
boundaries,
|
|
91
|
+
updateDateState
|
|
92
|
+
]);
|
|
87
93
|
return /* @__PURE__ */ jsxs(Box, {
|
|
88
94
|
className: cs("vui-calendar", className),
|
|
89
95
|
column: true,
|
|
@@ -98,22 +104,22 @@ const Calendar = vui((props, ref) => {
|
|
|
98
104
|
/* @__PURE__ */ jsx(CalendarHeader, {
|
|
99
105
|
nextDisabled: calendar.nextDisabled,
|
|
100
106
|
onChangeViewItem,
|
|
101
|
-
onSetTimeUnitMode:
|
|
107
|
+
onSetTimeUnitMode: setTimeUnitMode,
|
|
102
108
|
prevDisabled: calendar.prevDisabled,
|
|
103
109
|
timeUnitMode,
|
|
104
110
|
viewMonth: viewDate
|
|
105
111
|
}),
|
|
106
112
|
isDay(timeUnitMode) && /* @__PURE__ */ jsx(DayPicker, {
|
|
107
113
|
calendar,
|
|
108
|
-
onSelectDay
|
|
114
|
+
onSelectDay: onSelect
|
|
109
115
|
}),
|
|
110
116
|
isMonth(timeUnitMode) && /* @__PURE__ */ jsx(MonthPicker, {
|
|
111
117
|
calendar,
|
|
112
|
-
onSelectMonth
|
|
118
|
+
onSelectMonth: onSelect
|
|
113
119
|
}),
|
|
114
120
|
isYear(timeUnitMode) && /* @__PURE__ */ jsx(YearPicker, {
|
|
115
121
|
calendar,
|
|
116
|
-
onSelectYear
|
|
122
|
+
onSelectYear: onSelect
|
|
117
123
|
})
|
|
118
124
|
]
|
|
119
125
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"calendar.js","names":[],"sources":["../../src/calendar/calendar.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from 'react'\n\nimport type { CalendarProps, DateRange, FlowDirection,
|
|
1
|
+
{"version":3,"file":"calendar.js","names":[],"sources":["../../src/calendar/calendar.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react'\n\nimport type { CalendarProps, DateRange, FlowDirection, TimeUnitMode } from './calendar.types'\n\nimport Box from '../box'\nimport { omitThemingProps, useStyleConfig, vui } from '../core'\nimport { cs } from '../utils'\nimport { CalendarHeader, DayPicker, MonthPicker, YearPicker } from './components'\nimport { useCalendar, useDefaultViewMonth } from './hooks'\nimport {\n isDay,\n isExact,\n isFrom,\n isMonth,\n isTo,\n isYear,\n processSelectMonth,\n processSelectYear,\n processViewDate,\n} from './utils'\n\n/** Displays calendar. */\nexport const Calendar = vui<'div', CalendarProps>((props, ref) => {\n const {\n boundaries,\n className,\n fixedNumberOfWeeks = false,\n disabled,\n isStartDate,\n mode,\n onSelectDates,\n selectedDates,\n ...rest\n } = omitThemingProps(props)\n const styles = useStyleConfig('Calendar', props)\n\n const currentDateRef = useRef(isFrom(mode) || isExact(mode) ? selectedDates?.startDate : selectedDates?.endDate)\n\n const defaultViewMonth = useDefaultViewMonth({\n boundaries,\n selectedDate: currentDateRef.current,\n isStartDate,\n })\n\n const [timeUnitMode, setTimeUnitMode] = useState<TimeUnitMode>('day')\n const [viewDate, setViewDate] = useState<Date>(defaultViewMonth)\n\n const calendar = useCalendar({\n boundaries,\n mode,\n selectedDates,\n timeUnitMode,\n viewDate,\n fixedNumberOfWeeks,\n })\n\n /**\n * Effect to reset viewDate when selectedDates changes (onReset)\n * Compare timestamps to avoid resetting the view when the object reference changes but the date value hasn't.\n */\n useEffect(() => {\n const newDate = isFrom(mode) || isExact(mode) ? selectedDates?.startDate : selectedDates?.endDate\n if (newDate?.getTime() !== currentDateRef.current?.getTime()) {\n currentDateRef.current = newDate\n if (newDate) setViewDate(newDate)\n }\n }, [selectedDates, mode])\n\n /**\n * Send update date to parent component\n */\n const updateDateState = useCallback(\n (newDate: Date) => {\n const dateRange: DateRange = { ...selectedDates }\n if (isTo(mode)) dateRange.endDate = newDate\n else dateRange.startDate = newDate\n if (newDate && !disabled) onSelectDates?.(dateRange)\n },\n [selectedDates, mode, disabled, onSelectDates],\n )\n\n /**\n * Handles clicking next/prev in header\n */\n const onChangeViewItem = useCallback(\n (direction: FlowDirection) => {\n const newViewMonth = processViewDate(viewDate, direction, timeUnitMode, calendar.items)\n if (newViewMonth) setViewDate(newViewMonth)\n },\n [viewDate, timeUnitMode, calendar.items],\n )\n\n /**\n * Handles clicking on a day, month or year cell. The active timeUnitMode decides\n * how the clicked date is processed and which unit to drill down into next.\n */\n const onSelect = useCallback(\n (clickedDate: Date) => () => {\n let processedDate = clickedDate\n\n if (isMonth(timeUnitMode)) {\n processedDate = processSelectMonth(clickedDate, mode, boundaries)\n setTimeUnitMode('day')\n } else if (isYear(timeUnitMode)) {\n processedDate = processSelectYear(clickedDate, mode, boundaries)\n setTimeUnitMode('month')\n }\n\n updateDateState(processedDate)\n setViewDate(processedDate)\n },\n [timeUnitMode, mode, boundaries, updateDateState],\n )\n\n return (\n <Box\n className={cs('vui-calendar', className)}\n column\n cursor=\"default\"\n minW={280}\n position=\"relative\"\n ref={ref}\n w=\"fit-content\"\n {...styles}\n {...rest}\n >\n <CalendarHeader\n nextDisabled={calendar.nextDisabled}\n onChangeViewItem={onChangeViewItem}\n onSetTimeUnitMode={setTimeUnitMode}\n prevDisabled={calendar.prevDisabled}\n timeUnitMode={timeUnitMode}\n viewMonth={viewDate}\n />\n {isDay(timeUnitMode) && <DayPicker calendar={calendar} onSelectDay={onSelect} />}\n {isMonth(timeUnitMode) && <MonthPicker calendar={calendar} onSelectMonth={onSelect} />}\n {isYear(timeUnitMode) && <YearPicker calendar={calendar} onSelectYear={onSelect} />}\n </Box>\n )\n})\n\nCalendar.displayName = 'Calendar'\n\nexport default Calendar\n"],"mappings":";;;;;;;;;;;;;;;;AAsBA,MAAa,WAAW,KAA2B,OAAO,QAAQ;CAChE,MAAM,EACJ,YACA,WACA,qBAAqB,OACrB,UACA,aACA,MACA,eACA,eACA,GAAG,SACD,iBAAiB,KAAK;CAC1B,MAAM,SAAS,eAAe,YAAY,KAAK;CAE/C,MAAM,iBAAiB,OAAO,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,eAAe,YAAY,eAAe,OAAO;CAE/G,MAAM,mBAAmB,oBAAoB;EAC3C;EACA,cAAc,eAAe;EAC7B;CACF,CAAC;CAED,MAAM,CAAC,cAAc,mBAAmB,SAAuB,KAAK;CACpE,MAAM,CAAC,UAAU,eAAe,SAAe,gBAAgB;CAE/D,MAAM,WAAW,YAAY;EAC3B;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;;;;;CAMD,gBAAgB;EACd,MAAM,UAAU,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,eAAe,YAAY,eAAe;EAC1F,IAAI,SAAS,QAAQ,MAAM,eAAe,SAAS,QAAQ,GAAG;GAC5D,eAAe,UAAU;GACzB,IAAI,SAAS,YAAY,OAAO;EAClC;CACF,GAAG,CAAC,eAAe,IAAI,CAAC;;;;CAKxB,MAAM,kBAAkB,aACrB,YAAkB;EACjB,MAAM,YAAuB,EAAE,GAAG,cAAc;EAChD,IAAI,KAAK,IAAI,GAAG,UAAU,UAAU;OAC/B,UAAU,YAAY;EAC3B,IAAI,WAAW,CAAC,UAAU,gBAAgB,SAAS;CACrD,GACA;EAAC;EAAe;EAAM;EAAU;CAAa,CAC/C;;;;CAKA,MAAM,mBAAmB,aACtB,cAA6B;EAC5B,MAAM,eAAe,gBAAgB,UAAU,WAAW,cAAc,SAAS,KAAK;EACtF,IAAI,cAAc,YAAY,YAAY;CAC5C,GACA;EAAC;EAAU;EAAc,SAAS;CAAK,CACzC;;;;;CAMA,MAAM,WAAW,aACd,sBAA4B;EAC3B,IAAI,gBAAgB;EAEpB,IAAI,QAAQ,YAAY,GAAG;GACzB,gBAAgB,mBAAmB,aAAa,MAAM,UAAU;GAChE,gBAAgB,KAAK;EACvB,OAAO,IAAI,OAAO,YAAY,GAAG;GAC/B,gBAAgB,kBAAkB,aAAa,MAAM,UAAU;GAC/D,gBAAgB,OAAO;EACzB;EAEA,gBAAgB,aAAa;EAC7B,YAAY,aAAa;CAC3B,GACA;EAAC;EAAc;EAAM;EAAY;CAAe,CAClD;CAEA,OACE,qBAAC,KAAD;EACE,WAAW,GAAG,gBAAgB,SAAS;EACvC;EACA,QAAO;EACP,MAAM;EACN,UAAS;EACJ;EACL,GAAE;EACF,GAAI;EACJ,GAAI;YATN;GAWE,oBAAC,gBAAD;IACE,cAAc,SAAS;IACL;IAClB,mBAAmB;IACnB,cAAc,SAAS;IACT;IACd,WAAW;GACZ;GACA,MAAM,YAAY,KAAK,oBAAC,WAAD;IAAqB;IAAU,aAAa;GAAW;GAC9E,QAAQ,YAAY,KAAK,oBAAC,aAAD;IAAuB;IAAU,eAAe;GAAW;GACpF,OAAO,YAAY,KAAK,oBAAC,YAAD;IAAsB;IAAU,cAAc;GAAW;EAC/E;;AAET,CAAC;AAED,SAAS,cAAc"}
|
|
@@ -10,7 +10,8 @@ const size = 40;
|
|
|
10
10
|
* Header for the calendar
|
|
11
11
|
*/
|
|
12
12
|
const CalendarHeader = ({ nextDisabled, onChangeViewItem, onSetTimeUnitMode, prevDisabled, timeUnitMode, viewMonth }) => /* @__PURE__ */ jsxs(Box, {
|
|
13
|
-
borderBottom: "1px solid
|
|
13
|
+
borderBottom: "1px solid",
|
|
14
|
+
borderColor: "sandstone.main",
|
|
14
15
|
centerV: true,
|
|
15
16
|
className: cs("vui-calendar-header"),
|
|
16
17
|
children: [/* @__PURE__ */ jsx(Box, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"calendarHeader.js","names":[],"sources":["../../../src/calendar/components/calendarHeader.tsx"],"sourcesContent":["import type { FC } from 'react'\n\nimport type { FlowDirection, TimeUnitMode } from '../calendar.types'\n\nimport Box from '../../box'\nimport { IconButton } from '../../button'\nimport { cs } from '../../utils'\nimport { TimeUnitHeader } from './timeUnitHeader'\n\ntype Props = {\n nextDisabled?: boolean\n onChangeViewItem: (direction: FlowDirection) => void\n onSetTimeUnitMode: (mode: TimeUnitMode) => void\n prevDisabled?: boolean\n timeUnitMode: TimeUnitMode\n viewMonth: Date\n}\n\nconst size = 40\n\n/**\n * Header for the calendar\n */\nexport const CalendarHeader: FC<Props> = ({\n nextDisabled,\n onChangeViewItem,\n onSetTimeUnitMode,\n prevDisabled,\n timeUnitMode,\n viewMonth,\n}) => (\n <Box borderBottom=\"1px solid
|
|
1
|
+
{"version":3,"file":"calendarHeader.js","names":[],"sources":["../../../src/calendar/components/calendarHeader.tsx"],"sourcesContent":["import type { FC } from 'react'\n\nimport type { FlowDirection, TimeUnitMode } from '../calendar.types'\n\nimport Box from '../../box'\nimport { IconButton } from '../../button'\nimport { cs } from '../../utils'\nimport { TimeUnitHeader } from './timeUnitHeader'\n\ntype Props = {\n nextDisabled?: boolean\n onChangeViewItem: (direction: FlowDirection) => void\n onSetTimeUnitMode: (mode: TimeUnitMode) => void\n prevDisabled?: boolean\n timeUnitMode: TimeUnitMode\n viewMonth: Date\n}\n\nconst size = 40\n\n/**\n * Header for the calendar\n */\nexport const CalendarHeader: FC<Props> = ({\n nextDisabled,\n onChangeViewItem,\n onSetTimeUnitMode,\n prevDisabled,\n timeUnitMode,\n viewMonth,\n}) => (\n <Box borderBottom=\"1px solid\" borderColor=\"sandstone.main\" centerV className={cs('vui-calendar-header')}>\n <Box className=\"vui-calendar-header-left\">\n <TimeUnitHeader onSetTimeUnitMode={onSetTimeUnitMode} timeUnitMode={timeUnitMode} viewMonth={viewMonth} />\n </Box>\n <Box className=\"vui-calendar-header-right\" flex=\"1\" justifyContent=\"right\">\n <IconButton\n aria-label=\"previous\"\n className=\"icon\"\n disabled={prevDisabled}\n h={size}\n icon=\"uiChevronLeft\"\n onClick={() => onChangeViewItem('prev')}\n size=\"sm\"\n w={size}\n />\n <IconButton\n aria-label=\"next\"\n className=\"icon\"\n disabled={nextDisabled}\n h={size}\n icon=\"uiChevronRight\"\n onClick={() => onChangeViewItem('next')}\n size=\"sm\"\n w={size}\n />\n </Box>\n </Box>\n)\n"],"mappings":";;;;;;;AAkBA,MAAM,OAAO;;;;AAKb,MAAa,kBAA6B,EACxC,cACA,kBACA,mBACA,cACA,cACA,gBAEA,qBAAC,KAAD;CAAK,cAAa;CAAY,aAAY;CAAiB;CAAQ,WAAW,GAAG,qBAAqB;WAAtG,CACE,oBAAC,KAAD;EAAK,WAAU;YACb,oBAAC,gBAAD;GAAmC;GAAiC;GAAyB;EAAY;CACtG,IACL,qBAAC,KAAD;EAAK,WAAU;EAA4B,MAAK;EAAI,gBAAe;YAAnE,CACE,oBAAC,YAAD;GACE,cAAW;GACX,WAAU;GACV,UAAU;GACV,GAAG;GACH,MAAK;GACL,eAAe,iBAAiB,MAAM;GACtC,MAAK;GACL,GAAG;EACJ,IACD,oBAAC,YAAD;GACE,cAAW;GACX,WAAU;GACV,UAAU;GACV,GAAG;GACH,MAAK;GACL,eAAe,iBAAiB,MAAM;GACtC,MAAK;GACL,GAAG;EACJ,EACE;GACF"}
|
|
@@ -9,7 +9,7 @@ const MonthPicker = ({ calendar, onSelectMonth }) => /* @__PURE__ */ jsx(Calenda
|
|
|
9
9
|
gridTemplateRows: "repeat(4, 65px)",
|
|
10
10
|
children: calendar.items.map((item) => /* @__PURE__ */ jsx(CalendarItem, {
|
|
11
11
|
fontWeight: 500,
|
|
12
|
-
onClick: !item.isDisabled && onSelectMonth
|
|
12
|
+
onClick: !item.isDisabled && onSelectMonth?.(item.date) || void 0,
|
|
13
13
|
...item,
|
|
14
14
|
alignContent: "center",
|
|
15
15
|
textAlign: "center",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"monthPicker.js","names":["MonthItem"],"sources":["../../../src/calendar/components/monthPicker.tsx"],"sourcesContent":["import type { TimeResult } from '../calendar.types'\n\nimport { cs } from '../../utils'\nimport { CalendarItem as MonthItem, CalendarItemsContainer } from '../calendar.styles'\nimport { monthsShort } from '../consts'\n\ntype MonthPickerProps = {\n calendar: TimeResult\n onSelectMonth?: (date: Date) => void\n}\n\nexport const MonthPicker = ({ calendar, onSelectMonth }: MonthPickerProps) => (\n <CalendarItemsContainer className={cs('vui-month-picker')} gridTemplateRows=\"repeat(4, 65px)\">\n {calendar.items.map(item => (\n <MonthItem\n fontWeight={500}\n key={item.date.getTime()}\n onClick={(!item.isDisabled && onSelectMonth
|
|
1
|
+
{"version":3,"file":"monthPicker.js","names":["MonthItem"],"sources":["../../../src/calendar/components/monthPicker.tsx"],"sourcesContent":["import type { TimeResult } from '../calendar.types'\n\nimport { cs } from '../../utils'\nimport { CalendarItem as MonthItem, CalendarItemsContainer } from '../calendar.styles'\nimport { monthsShort } from '../consts'\n\ntype MonthPickerProps = {\n calendar: TimeResult\n onSelectMonth?: (date: Date) => void\n}\n\nexport const MonthPicker = ({ calendar, onSelectMonth }: MonthPickerProps) => (\n <CalendarItemsContainer className={cs('vui-month-picker')} gridTemplateRows=\"repeat(4, 65px)\">\n {calendar.items.map(item => (\n <MonthItem\n fontWeight={500}\n key={item.date.getTime()}\n onClick={(!item.isDisabled && onSelectMonth?.(item.date)) || undefined}\n {...item}\n alignContent=\"center\"\n textAlign=\"center\"\n >\n {monthsShort[item.date.getUTCMonth()]}\n </MonthItem>\n ))}\n </CalendarItemsContainer>\n)\n"],"mappings":";;;;;;AAWA,MAAa,eAAe,EAAE,UAAU,oBACtC,oBAAC,wBAAD;CAAwB,WAAW,GAAG,kBAAkB;CAAG,kBAAiB;WACzE,SAAS,MAAM,KAAI,SAClB,oBAACA,cAAD;EACE,YAAY;EAEZ,SAAU,CAAC,KAAK,cAAc,gBAAgB,KAAK,IAAI,KAAM;EAC7D,GAAI;EACJ,cAAa;EACb,WAAU;YAET,YAAY,KAAK,KAAK,YAAY;CAC1B,GAPJ,KAAK,KAAK,QAAQ,CAOd,CACZ;AACqB"}
|
package/dist/svg/helpers.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { __DEV__ } from "../utils/consts.js";
|
|
2
|
+
|
|
1
3
|
//#region src/svg/helpers.ts
|
|
2
4
|
const SVG_NAMESPACE = "http://www.w3.org/2000/svg";
|
|
3
5
|
/**
|
|
@@ -30,17 +32,24 @@ const ALLOWED_ELEMENTS = /* @__PURE__ */ new Set([
|
|
|
30
32
|
"text",
|
|
31
33
|
"tspan"
|
|
32
34
|
]);
|
|
35
|
+
function warnRemoval(kind, name) {
|
|
36
|
+
if (true) console.warn(`[Svg] Removed unsafe SVG ${kind} \`${name}\`.`);
|
|
37
|
+
}
|
|
33
38
|
/** Removes disallowed elements, event handler attributes and external references. */
|
|
34
39
|
function sanitizeElement(element) {
|
|
35
40
|
if (element.namespaceURI !== SVG_NAMESPACE || !ALLOWED_ELEMENTS.has(element.tagName)) {
|
|
41
|
+
warnRemoval("element", element.tagName);
|
|
36
42
|
element.remove();
|
|
37
43
|
return;
|
|
38
44
|
}
|
|
39
45
|
for (const attr of Array.from(element.attributes)) {
|
|
40
|
-
const name = attr.
|
|
46
|
+
const name = attr.localName.toLowerCase();
|
|
41
47
|
const isEventHandler = name.startsWith("on");
|
|
42
|
-
const isExternalRef =
|
|
43
|
-
if (isEventHandler || isExternalRef)
|
|
48
|
+
const isExternalRef = name === "href" && !attr.value.trim().startsWith("#");
|
|
49
|
+
if (isEventHandler || isExternalRef) {
|
|
50
|
+
warnRemoval("attribute", attr.name);
|
|
51
|
+
element.removeAttribute(attr.name);
|
|
52
|
+
}
|
|
44
53
|
}
|
|
45
54
|
for (const child of Array.from(element.children)) sanitizeElement(child);
|
|
46
55
|
}
|
package/dist/svg/helpers.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.js","names":[],"sources":["../../src/svg/helpers.ts"],"sourcesContent":["import type { Dict } from '../utils'\nimport type { SvgState } from './svg.types'\n\nconst SVG_NAMESPACE = 'http://www.w3.org/2000/svg'\n\n/**\n * SVG elements allowed in icon content. Notably excludes 'script' and\n * 'foreignObject' (which switches parsing back to HTML and enables\n * DOM clobbering / XSS). Comparison is case-sensitive per XML parsing.\n */\nconst ALLOWED_ELEMENTS = new Set([\n 'svg',\n 'g',\n 'path',\n 'circle',\n 'ellipse',\n 'rect',\n 'line',\n 'polyline',\n 'polygon',\n 'defs',\n 'title',\n 'desc',\n 'symbol',\n 'use',\n 'linearGradient',\n 'radialGradient',\n 'stop',\n 'clipPath',\n 'mask',\n 'pattern',\n 'marker',\n 'text',\n 'tspan',\n])\n\n/** Removes disallowed elements, event handler attributes and external references. */\nfunction sanitizeElement(element: Element) {\n if (element.namespaceURI !== SVG_NAMESPACE || !ALLOWED_ELEMENTS.has(element.tagName)) {\n element.remove()\n return\n }\n\n for (const attr of Array.from(element.attributes)) {\n const name = attr.
|
|
1
|
+
{"version":3,"file":"helpers.js","names":[],"sources":["../../src/svg/helpers.ts"],"sourcesContent":["import type { Dict } from '../utils'\nimport type { SvgState } from './svg.types'\n\nimport { __DEV__ } from '../utils'\n\nconst SVG_NAMESPACE = 'http://www.w3.org/2000/svg'\n\n/**\n * SVG elements allowed in icon content. Notably excludes 'script' and\n * 'foreignObject' (which switches parsing back to HTML and enables\n * DOM clobbering / XSS). Comparison is case-sensitive per XML parsing.\n */\nconst ALLOWED_ELEMENTS = new Set([\n 'svg',\n 'g',\n 'path',\n 'circle',\n 'ellipse',\n 'rect',\n 'line',\n 'polyline',\n 'polygon',\n 'defs',\n 'title',\n 'desc',\n 'symbol',\n 'use',\n 'linearGradient',\n 'radialGradient',\n 'stop',\n 'clipPath',\n 'mask',\n 'pattern',\n 'marker',\n 'text',\n 'tspan',\n])\n\nfunction warnRemoval(kind: 'element' | 'attribute', name: string) {\n if (__DEV__) console.warn(`[Svg] Removed unsafe SVG ${kind} \\`${name}\\`.`)\n}\n\n/** Removes disallowed elements, event handler attributes and external references. */\nfunction sanitizeElement(element: Element) {\n if (element.namespaceURI !== SVG_NAMESPACE || !ALLOWED_ELEMENTS.has(element.tagName)) {\n warnRemoval('element', element.tagName)\n element.remove()\n return\n }\n\n for (const attr of Array.from(element.attributes)) {\n const name = attr.localName.toLowerCase()\n const isEventHandler = name.startsWith('on')\n const isExternalRef = name === 'href' && !attr.value.trim().startsWith('#')\n\n if (isEventHandler || isExternalRef) {\n warnRemoval('attribute', attr.name)\n element.removeAttribute(attr.name)\n }\n }\n\n for (const child of Array.from(element.children)) {\n sanitizeElement(child)\n }\n}\n\n/** Parses an SVG string into an inert, sanitized svg element. Returns undefined for invalid content. */\nexport function parseSvg(html: string) {\n // DOMParser produces an inert document: nothing executes or loads while parsing\n const doc = new DOMParser().parseFromString(html, 'image/svg+xml')\n const root = doc.documentElement\n\n // A parse error yields a 'parsererror' root, which also fails this check\n if (root.namespaceURI !== SVG_NAMESPACE || root.tagName !== 'svg') return undefined\n\n sanitizeElement(root)\n\n return root\n}\n\n/** Returns an object with given element's HTML attributes. */\nexport function getAttributes(element?: Element) {\n if (!element) return {}\n\n const attrs = Array.from(element.attributes)\n\n return attrs.reduce((props: Dict<string>, attr) => {\n const { name, value } = attr\n props[name] = value\n return props\n }, {})\n}\n\n/** Returns the inner content of a sanitized svg element. */\nexport function getSvgContent(element?: Element) {\n return element?.innerHTML ?? ''\n}\n\n/** Returns object with initial state values. */\nexport function initState(): SvgState {\n return { content: '', svgAttributes: {} }\n}\n"],"mappings":";;;AAKA,MAAM,gBAAgB;;;;;;AAOtB,MAAM,mCAAmB,IAAI,IAAI;CAC/B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,SAAS,YAAY,MAA+B,MAAc;CAChE,UAAa,QAAQ,KAAK,4BAA4B,KAAK,KAAK,KAAK,IAAI;AAC3E;;AAGA,SAAS,gBAAgB,SAAkB;CACzC,IAAI,QAAQ,iBAAiB,iBAAiB,CAAC,iBAAiB,IAAI,QAAQ,OAAO,GAAG;EACpF,YAAY,WAAW,QAAQ,OAAO;EACtC,QAAQ,OAAO;EACf;CACF;CAEA,KAAK,MAAM,QAAQ,MAAM,KAAK,QAAQ,UAAU,GAAG;EACjD,MAAM,OAAO,KAAK,UAAU,YAAY;EACxC,MAAM,iBAAiB,KAAK,WAAW,IAAI;EAC3C,MAAM,gBAAgB,SAAS,UAAU,CAAC,KAAK,MAAM,KAAK,CAAC,CAAC,WAAW,GAAG;EAE1E,IAAI,kBAAkB,eAAe;GACnC,YAAY,aAAa,KAAK,IAAI;GAClC,QAAQ,gBAAgB,KAAK,IAAI;EACnC;CACF;CAEA,KAAK,MAAM,SAAS,MAAM,KAAK,QAAQ,QAAQ,GAC7C,gBAAgB,KAAK;AAEzB;;AAGA,SAAgB,SAAS,MAAc;CAGrC,MAAM,OADM,IAAI,UAAU,CAAC,CAAC,gBAAgB,MAAM,eACnC,CAAC,CAAC;CAGjB,IAAI,KAAK,iBAAiB,iBAAiB,KAAK,YAAY,OAAO,OAAO;CAE1E,gBAAgB,IAAI;CAEpB,OAAO;AACT;;AAGA,SAAgB,cAAc,SAAmB;CAC/C,IAAI,CAAC,SAAS,OAAO,CAAC;CAItB,OAFc,MAAM,KAAK,QAAQ,UAEtB,CAAC,CAAC,QAAQ,OAAqB,SAAS;EACjD,MAAM,EAAE,MAAM,UAAU;EACxB,MAAM,QAAQ;EACd,OAAO;CACT,GAAG,CAAC,CAAC;AACP;;AAGA,SAAgB,cAAc,SAAmB;CAC/C,OAAO,SAAS,aAAa;AAC/B;;AAGA,SAAgB,YAAsB;CACpC,OAAO;EAAE,SAAS;EAAI,eAAe,CAAC;CAAE;AAC1C"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@veracity/vui",
|
|
3
|
-
"version": "5.3.1
|
|
3
|
+
"version": "5.3.1",
|
|
4
4
|
"description": "Veracity UI is a React component library crafted for use within Veracity applications and pages. Based on Styled Components and @xstyled.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"tanstack-intent"
|