@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.
@@ -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
- * Handles clicking next/prev in header
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
- const onSelectDay = (clickedDate) => () => {
47
- updateDateState(clickedDate);
48
- setViewDate(clickedDate);
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
- * Handles clicking on a month
48
+ * Send update date to parent component
52
49
  */
53
- const onSelectMonth = (clickedDate) => () => {
54
- const processedNewDate = processSelectMonth(clickedDate, mode, boundaries);
55
- updateDateState(processedNewDate);
56
- setViewDate(processedNewDate);
57
- setTimeUnitMode("day");
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 on a year
62
+ * Handles clicking next/prev in header
61
63
  */
62
- const onSelectYear = (clickedDate) => () => {
63
- const processedNewDate = processSelectYear(clickedDate, mode, boundaries);
64
- updateDateState(processedNewDate);
65
- setViewDate(processedNewDate);
66
- setTimeUnitMode("month");
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
- * Send update date to parent component
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 updateDateState = (newDate) => {
72
- const dateRange = { ...selectedDates };
73
- if (dateRange) {
74
- if (isTo(mode)) dateRange.endDate = newDate;
75
- else dateRange.startDate = newDate;
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
- if (newDate && !disabled) onSelectDates && onSelectDates(dateRange);
78
- };
79
- const calendar = calendarRef.current = useCalendar({
80
- boundaries,
81
- mode,
82
- selectedDates,
85
+ updateDateState(processedDate);
86
+ setViewDate(processedDate);
87
+ }, [
83
88
  timeUnitMode,
84
- viewDate,
85
- fixedNumberOfWeeks
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: (mode) => setTimeUnitMode(mode),
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, TimeResult, 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 /**\n * Effect to reset viewDate when selectedDates changes (onReset)\n */\n useEffect(() => {\n currentDateRef.current = isFrom(mode) || isExact(mode) ? selectedDates?.startDate : selectedDates?.endDate\n currentDateRef.current && setViewDate(currentDateRef.current)\n }, [selectedDates])\n\n const calendarRef = useRef<TimeResult | null>(null)\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 /**\n * Handles clicking next/prev in header\n */\n const onChangeViewItem = (direction: FlowDirection) => {\n const newViewMonth = processViewDate(viewDate, direction, timeUnitMode, calendarRef?.current?.items)\n newViewMonth && setViewDate(newViewMonth)\n }\n\n /**\n * Handles clicking on a day\n */\n const onSelectDay = (clickedDate: Date) => () => {\n updateDateState(clickedDate)\n setViewDate(clickedDate)\n }\n\n /**\n * Handles clicking on a month\n */\n const onSelectMonth = (clickedDate: Date) => () => {\n const processedNewDate = processSelectMonth(clickedDate, mode, boundaries)\n updateDateState(processedNewDate)\n setViewDate(processedNewDate)\n setTimeUnitMode('day')\n }\n\n /**\n * Handles clicking on a year\n */\n const onSelectYear = (clickedDate: Date) => () => {\n const processedNewDate = processSelectYear(clickedDate, mode, boundaries)\n updateDateState(processedNewDate)\n setViewDate(processedNewDate)\n setTimeUnitMode('month')\n }\n\n /**\n * Send update date to parent component\n */\n const updateDateState = (newDate: Date) => {\n const dateRange: DateRange = { ...selectedDates }\n\n if (dateRange) {\n if (isTo(mode)) dateRange.endDate = newDate\n else dateRange.startDate = newDate\n }\n\n if (newDate && !disabled) onSelectDates && onSelectDates(dateRange)\n }\n\n const calendar = (calendarRef.current = useCalendar({\n boundaries,\n mode,\n selectedDates,\n timeUnitMode,\n viewDate,\n fixedNumberOfWeeks,\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={(mode: TimeUnitMode) => setTimeUnitMode(mode)}\n prevDisabled={calendar.prevDisabled}\n timeUnitMode={timeUnitMode}\n viewMonth={viewDate}\n />\n {isDay(timeUnitMode) && <DayPicker calendar={calendar} onSelectDay={onSelectDay} />}\n {isMonth(timeUnitMode) && <MonthPicker calendar={calendar} onSelectMonth={onSelectMonth} />}\n {isYear(timeUnitMode) && <YearPicker calendar={calendar} onSelectYear={onSelectYear} />}\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;;;;CAK/G,gBAAgB;EACd,eAAe,UAAU,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,eAAe,YAAY,eAAe;EACnG,eAAe,WAAW,YAAY,eAAe,OAAO;CAC9D,GAAG,CAAC,aAAa,CAAC;CAElB,MAAM,cAAc,OAA0B,IAAI;CAElD,MAAM,mBAAmB,oBAAoB;EAC3C;EACA,cAAc,eAAe;EAC7B;CACF,CAAC;CAED,MAAM,CAAC,cAAc,mBAAmB,SAAuB,KAAK;CACpE,MAAM,CAAC,UAAU,eAAe,SAAe,gBAAgB;;;;CAK/D,MAAM,oBAAoB,cAA6B;EACrD,MAAM,eAAe,gBAAgB,UAAU,WAAW,cAAc,aAAa,SAAS,KAAK;EACnG,gBAAgB,YAAY,YAAY;CAC1C;;;;CAKA,MAAM,eAAe,sBAA4B;EAC/C,gBAAgB,WAAW;EAC3B,YAAY,WAAW;CACzB;;;;CAKA,MAAM,iBAAiB,sBAA4B;EACjD,MAAM,mBAAmB,mBAAmB,aAAa,MAAM,UAAU;EACzE,gBAAgB,gBAAgB;EAChC,YAAY,gBAAgB;EAC5B,gBAAgB,KAAK;CACvB;;;;CAKA,MAAM,gBAAgB,sBAA4B;EAChD,MAAM,mBAAmB,kBAAkB,aAAa,MAAM,UAAU;EACxE,gBAAgB,gBAAgB;EAChC,YAAY,gBAAgB;EAC5B,gBAAgB,OAAO;CACzB;;;;CAKA,MAAM,mBAAmB,YAAkB;EACzC,MAAM,YAAuB,EAAE,GAAG,cAAc;EAEhD,IAAI,WAAW;GACb,IAAI,KAAK,IAAI,GAAG,UAAU,UAAU;QAC/B,UAAU,YAAY;EAC7B;EAEA,IAAI,WAAW,CAAC,UAAU,iBAAiB,cAAc,SAAS;CACpE;CAEA,MAAM,WAAY,YAAY,UAAU,YAAY;EAClD;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,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,oBAAoB,SAAuB,gBAAgB,IAAI;IAC/D,cAAc,SAAS;IACT;IACd,WAAW;GACZ;GACA,MAAM,YAAY,KAAK,oBAAC,WAAD;IAAqB;IAAuB;GAAc;GACjF,QAAQ,YAAY,KAAK,oBAAC,aAAD;IAAuB;IAAyB;GAAgB;GACzF,OAAO,YAAY,KAAK,oBAAC,YAAD;IAAsB;IAAwB;GAAe;EACnF;;AAET,CAAC;AAED,SAAS,cAAc"}
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 lightgray",
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 lightgray\" 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;CAAsB;CAAQ,WAAW,GAAG,qBAAqB;WAAnF,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"}
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 && onSelectMonth(item.date) || void 0,
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 && 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,iBAAiB,cAAc,KAAK,IAAI,KAAM;EAC5E,GAAI;EACJ,cAAa;EACb,WAAU;YAET,YAAY,KAAK,KAAK,YAAY;CAC1B,GAPJ,KAAK,KAAK,QAAQ,CAOd,CACZ;AACqB"}
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"}
@@ -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.name.toLowerCase();
46
+ const name = attr.localName.toLowerCase();
41
47
  const isEventHandler = name.startsWith("on");
42
- const isExternalRef = (name === "href" || name === "xlink:href") && !attr.value.trim().startsWith("#");
43
- if (isEventHandler || isExternalRef) element.removeAttribute(attr.name);
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
  }
@@ -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.name.toLowerCase()\n const isEventHandler = name.startsWith('on')\n const isExternalRef = (name === 'href' || name === 'xlink:href') && !attr.value.trim().startsWith('#')\n\n if (isEventHandler || isExternalRef) {\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":";AAGA,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;;AAGD,SAAS,gBAAgB,SAAkB;CACzC,IAAI,QAAQ,iBAAiB,iBAAiB,CAAC,iBAAiB,IAAI,QAAQ,OAAO,GAAG;EACpF,QAAQ,OAAO;EACf;CACF;CAEA,KAAK,MAAM,QAAQ,MAAM,KAAK,QAAQ,UAAU,GAAG;EACjD,MAAM,OAAO,KAAK,KAAK,YAAY;EACnC,MAAM,iBAAiB,KAAK,WAAW,IAAI;EAC3C,MAAM,iBAAiB,SAAS,UAAU,SAAS,iBAAiB,CAAC,KAAK,MAAM,KAAK,CAAC,CAAC,WAAW,GAAG;EAErG,IAAI,kBAAkB,eACpB,QAAQ,gBAAgB,KAAK,IAAI;CAErC;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"}
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-alpha.422947.2608191243",
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"