@sanity/rich-date-input 3.0.3 → 3.0.5

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/README.md CHANGED
@@ -22,7 +22,7 @@ import {defineConfig} from 'sanity'
22
22
  import {richDate} from '@sanity/rich-date-input'
23
23
 
24
24
  export default defineConfig({
25
- //...
25
+ // ...
26
26
  plugins: [richDate()],
27
27
  })
28
28
  ```
@@ -41,7 +41,7 @@ export default defineType({
41
41
  name: 'scheduledAt',
42
42
  title: 'Scheduled at',
43
43
  type: 'richDate',
44
- //this will take the same options available on the datetime type: https://www.sanity.io/docs/datetime-type
44
+ // this will take the same options available on the datetime type: https://www.sanity.io/docs/datetime-type
45
45
  options: {
46
46
  timeStep: 30,
47
47
  },
package/dist/index.esm.js CHANGED
@@ -1,16 +1,16 @@
1
- import { DateTimeInput, unset, set, ObjectInputMember, defineType, defineField, definePlugin } from 'sanity';
1
+ import { unset, set, DateTimeInput, ObjectInputMember, defineType, defineField, definePlugin } from 'sanity';
2
2
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
- import { Box, Autocomplete, Card, Text, Button, Flex, Dialog } from '@sanity/ui';
3
+ import { Button, Box, Autocomplete, Card, Text, Flex, Dialog } from '@sanity/ui';
4
+ import { useCallback, useState } from 'react';
5
+ import { formatInTimeZone, zonedTimeToUtc, getTimezoneOffset } from 'date-fns-tz';
4
6
  import { getTimeZones } from '@vvo/tzdb';
5
- import { formatInTimeZone, zonedTimeToUtc } from 'date-fns-tz';
6
- import { SearchIcon, EarthAmericasIcon } from '@sanity/icons';
7
- import { useState, useCallback } from 'react';
7
+ import { EarthAmericasIcon, SearchIcon } from '@sanity/icons';
8
8
  const unlocalizeDateTime = (datetime, timezone) => {
9
9
  return formatInTimeZone(datetime, timezone, "yyyy-MM-dd HH:mm:ss");
10
10
  };
11
11
  const getConstructedUTCDate = (utc, offset) => {
12
12
  const date = new Date(utc);
13
- const currentOffset = ( /* @__PURE__ */new Date()).getTimezoneOffset() * -1;
13
+ const currentOffset = date.getTimezoneOffset() * -1;
14
14
  const diff = currentOffset - offset;
15
15
  const fakeUTCDate = new Date(date.getTime() - diff * 60 * 1e3);
16
16
  return fakeUTCDate.toISOString();
@@ -32,30 +32,33 @@ const allTimezones = getTimeZones().map(tz => {
32
32
  };
33
33
  });
34
34
  const RelativeDateTimePicker = props => {
35
- var _a, _b;
36
- const value = props.dateValue;
37
- const timezone = (_a = value == null ? void 0 : value.timezone) != null ? _a : Intl.DateTimeFormat().resolvedOptions().timeZone;
38
- const offset = (_b = value == null ? void 0 : value.offset) != null ? _b : ( /* @__PURE__ */new Date()).getTimezoneOffset() * -1;
39
- const handleDateChange = patch => {
40
- const patches = [];
35
+ const {
36
+ dateValue: value,
37
+ onChange
38
+ } = props;
39
+ const handleDateChange = useCallback(patch => {
40
+ var _a;
41
+ const timezone = (_a = value == null ? void 0 : value.timezone) != null ? _a : Intl.DateTimeFormat().resolvedOptions().timeZone;
41
42
  const newDatetime = patch == null ? void 0 : patch.value;
42
43
  if (!newDatetime || !("type" in patch) || patch.type !== "set") {
43
- props.onChange(unset());
44
+ onChange(unset());
44
45
  return;
45
46
  }
46
47
  const desiredDateTime = unlocalizeDateTime(newDatetime, Intl.DateTimeFormat().resolvedOptions().timeZone);
47
- const utcDate = zonedTimeToUtc(desiredDateTime, timezone).toISOString();
48
- const localDate = formatInTimeZone(utcDate, timezone, "yyyy-MM-dd'T'HH:mm:ssXXX");
49
- patches.push(set(utcDate, ["utc"]));
48
+ const newUtcDateObject = zonedTimeToUtc(desiredDateTime, timezone);
49
+ const newOffset = getTimezoneOffset(timezone, newUtcDateObject) / 60 / 1e3;
50
+ const localDate = formatInTimeZone(newUtcDateObject, timezone, "yyyy-MM-dd'T'HH:mm:ssXXX");
51
+ const patches = [];
52
+ patches.push(set(newUtcDateObject.toISOString(), ["utc"]));
50
53
  patches.push(set(localDate, ["local"]));
51
54
  if (!(value == null ? void 0 : value.timezone)) {
52
55
  patches.push(set(timezone, ["timezone"]));
53
56
  }
54
- if (!(value == null ? void 0 : value.offset)) {
55
- patches.push(set(offset, ["offset"]));
57
+ if ((value == null ? void 0 : value.offset) !== newOffset) {
58
+ patches.push(set(newOffset, ["offset"]));
56
59
  }
57
- props.onChange(patches);
58
- };
60
+ onChange(patches);
61
+ }, [onChange, value]);
59
62
  const dateToDisplay = (value == null ? void 0 : value.utc) ? getConstructedUTCDate(value.utc, value.offset) : "";
60
63
  return /* @__PURE__ */jsx(DateTimeInput, {
61
64
  ...props,
@@ -63,6 +66,27 @@ const RelativeDateTimePicker = props => {
63
66
  value: dateToDisplay
64
67
  });
65
68
  };
69
+ const TimezoneButton = props => {
70
+ var _a, _b, _c, _d, _e;
71
+ const {
72
+ onClick,
73
+ timezone
74
+ } = props;
75
+ const currentTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
76
+ const label = (_e = (_c = (_a = allTimezones.find(tz => tz.name === timezone)) == null ? void 0 : _a.abbreviation) != null ? _c : (_b = allTimezones.find(tz => tz.name === currentTimezone)) == null ? void 0 : _b.abbreviation) != null ? _e : (_d = allTimezones.find(tz => tz.group.includes(currentTimezone))) == null ? void 0 : _d.abbreviation;
77
+ return /* @__PURE__ */jsx(Button, {
78
+ fontSize: 1,
79
+ style: {
80
+ width: "100%"
81
+ },
82
+ justify: "flex-start",
83
+ icon: EarthAmericasIcon,
84
+ mode: "ghost",
85
+ onClick,
86
+ text: "".concat(label),
87
+ "aria-label": "Select a timezone"
88
+ });
89
+ };
66
90
  const TimezoneSelector = props => {
67
91
  var _a, _b;
68
92
  const {
@@ -72,25 +96,25 @@ const TimezoneSelector = props => {
72
96
  const currentTz = allTimezones.find(tz => tz.name === (value == null ? void 0 : value.timezone));
73
97
  const userTzName = Intl.DateTimeFormat().resolvedOptions().timeZone;
74
98
  const userTz = (_a = allTimezones.find(tz => tz.name === userTzName)) != null ? _a : allTimezones.find(tz => tz.group.includes(userTzName));
75
- const handleTimezoneChange = selectedTz => {
76
- var _a2, _b2;
99
+ const handleTimezoneChange = useCallback(selectedTz => {
100
+ var _a2;
77
101
  const newTimezone = (_a2 = allTimezones.find(tz => tz.value === selectedTz)) != null ? _a2 : userTz;
78
- const offset = (_b2 = newTimezone.currentTimeOffsetInMinutes) != null ? _b2 : 0;
79
102
  const timezonePatch = set(newTimezone.name, ["timezone"]);
80
- const offsetPatch = set(offset, ["offset"]);
81
- const patches = [timezonePatch, offsetPatch];
103
+ const patches = [timezonePatch];
82
104
  if (value == null ? void 0 : value.utc) {
83
105
  const desiredDateTime = unlocalizeDateTime(value.utc, value.timezone);
84
- const newUtcDate = zonedTimeToUtc(desiredDateTime, newTimezone.name).toISOString();
85
- const newLocalDate = formatInTimeZone(newUtcDate, newTimezone.name, "yyyy-MM-dd'T'HH:mm:ssXXX");
86
- patches.push(set(newUtcDate, ["utc"]));
106
+ const newUtcDateObject = zonedTimeToUtc(desiredDateTime, newTimezone.name);
107
+ const newOffset = getTimezoneOffset(newTimezone.name, newUtcDateObject) / 60 / 1e3;
108
+ const newLocalDate = formatInTimeZone(newUtcDateObject.toISOString(), newTimezone.name, "yyyy-MM-dd'T'HH:mm:ssXXX");
109
+ patches.push(set(newUtcDateObject.toISOString(), ["utc"]));
87
110
  patches.push(set(newLocalDate, ["local"]));
111
+ patches.push(set(newOffset, ["offset"]));
88
112
  }
89
113
  onChange(patches);
90
- };
114
+ }, [onChange, userTz, value]);
91
115
  return (
92
- //taken from Scheduled Publishing, again!
93
- //https://github.com/sanity-io/sanity-plugin-scheduled-publishing/blob/bb282e3df9a8a73df37fab8ee1fdd0e2430745be/src/components/dialogs/DialogTimeZone.tsx#L100
116
+ // taken from Scheduled Publishing, again!
117
+ // https://github.com/sanity-io/sanity-plugin-scheduled-publishing/blob/bb282e3df9a8a73df37fab8ee1fdd0e2430745be/src/components/dialogs/DialogTimeZone.tsx#L100
94
118
  /* @__PURE__ */
95
119
  jsx(Box, {
96
120
  padding: 4,
@@ -142,27 +166,6 @@ const TimezoneSelector = props => {
142
166
  })
143
167
  );
144
168
  };
145
- const TimezoneButton = props => {
146
- var _a, _b, _c, _d, _e;
147
- const {
148
- onClick,
149
- timezone
150
- } = props;
151
- const currentTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
152
- const label = (_e = (_c = (_a = allTimezones.find(tz => tz.name === timezone)) == null ? void 0 : _a.abbreviation) != null ? _c : (_b = allTimezones.find(tz => tz.name === currentTimezone)) == null ? void 0 : _b.abbreviation) != null ? _e : (_d = allTimezones.find(tz => tz.group.includes(currentTimezone))) == null ? void 0 : _d.abbreviation;
153
- return /* @__PURE__ */jsx(Button, {
154
- fontSize: 1,
155
- style: {
156
- width: "100%"
157
- },
158
- justify: "flex-start",
159
- icon: EarthAmericasIcon,
160
- mode: "ghost",
161
- onClick,
162
- text: "".concat(label),
163
- "aria-label": "Select a timezone"
164
- });
165
- };
166
169
  const RichDateInput = props => {
167
170
  const {
168
171
  onChange,
@@ -1 +1 @@
1
- {"version":3,"file":"index.esm.js","sources":["../src/utils/index.ts","../src/components/RelativeDateTimePicker.tsx","../src/components/TimezoneSelector.tsx","../src/components/TimezoneButton.tsx","../src/components/RichDateInput.tsx","../src/schema.ts","../src/index.ts"],"sourcesContent":["import {getTimeZones} from '@vvo/tzdb'\nimport {NormalizedTimeZone} from '../types'\nimport {formatInTimeZone} from 'date-fns-tz'\n\nexport const unlocalizeDateTime = (datetime: string, timezone: string): string => {\n return formatInTimeZone(datetime, timezone, 'yyyy-MM-dd HH:mm:ss')\n}\n\n/* We have to \"fake\" a UTC date to make the datepicker look \"right\"\n * to the user. For example, if someone sets 7:00AM PST, which is 3PM UTC\n * and I am on the east coast, I want to have 12:00PM UTC, which will look like 7:00AM to me\n * In other words, UTC minus 3 hours, or (UTC(my offset - their offset))\n * this is purely cosmetic and should not be saved at all\n */\nexport const getConstructedUTCDate = (utc: string, offset: number): string => {\n const date = new Date(utc)\n const currentOffset = new Date().getTimezoneOffset() * -1\n const diff = currentOffset - offset\n const fakeUTCDate = new Date(date.getTime() - diff * 60 * 1000)\n return fakeUTCDate.toISOString()\n}\n\n//keep some consistency with scheduled publishing\n//https://github.com/sanity-io/sanity-plugin-scheduled-publishing/blob/bb282e3df9a8a73df37fab8ee1fdd0e2430745be/src/hooks/useTimeZone.tsx#L17\nexport const allTimezones = getTimeZones().map((tz) => {\n return {\n abbreviation: tz.abbreviation,\n alternativeName: tz.alternativeName,\n mainCities: tz.mainCities.join(', '),\n // Main time zone name 'Africa/Dar_es_Salaam'\n name: tz.name,\n // Time zone name with underscores removed\n namePretty: tz.name.replaceAll('_', ' '),\n offset: tz.currentTimeFormat.split(' ')[0],\n // all searchable text - this is transformed before being rendered in `<AutoComplete>`\n value: `${tz.currentTimeFormat} ${tz.abbreviation} ${tz.name}`,\n currentTimeOffsetInMinutes: tz.currentTimeOffsetInMinutes,\n group: tz.group,\n } as NormalizedTimeZone\n})\n","import {DateTimeInput, FormPatch, PatchEvent, InputProps, set, unset} from 'sanity'\n\nimport {getConstructedUTCDate, unlocalizeDateTime} from '../utils'\nimport {RichDate} from '../types'\nimport {formatInTimeZone, zonedTimeToUtc} from 'date-fns-tz'\n\ninterface RelativeDateTimePickerProps extends Omit<InputProps, 'renderDefault'> {\n dateValue?: RichDate\n}\n\nexport const RelativeDateTimePicker = (props: RelativeDateTimePickerProps) => {\n const value = props.dateValue\n const timezone = value?.timezone ?? Intl.DateTimeFormat().resolvedOptions().timeZone\n /*\n * if our offset is not coming from a lib, we have to reverse it\n * to get the real offset used everywhere\n * https://momentjscom.readthedocs.io/en/latest/moment/03-manipulating/09-utc-offset/\n */\n const offset = value?.offset ?? new Date().getTimezoneOffset() * -1\n const handleDateChange = (patch: FormPatch | PatchEvent | FormPatch[]) => {\n const patches = []\n const newDatetime = (patch as unknown as {value: string})?.value\n if (!newDatetime || !('type' in patch) || patch.type !== 'set') {\n props.onChange(unset())\n return\n }\n\n //get what time the user \"meant\" to set without tz info\n //since the datepicker always localizes to the user's timezone\n const desiredDateTime = unlocalizeDateTime(\n newDatetime,\n Intl.DateTimeFormat().resolvedOptions().timeZone,\n )\n\n //use the user-selected timezone here\n const utcDate = zonedTimeToUtc(desiredDateTime, timezone).toISOString()\n const localDate = formatInTimeZone(utcDate, timezone, \"yyyy-MM-dd'T'HH:mm:ssXXX\")\n\n patches.push(set(utcDate, ['utc']))\n patches.push(set(localDate, ['local']))\n\n if (!value?.timezone) {\n patches.push(set(timezone, ['timezone']))\n }\n\n if (!value?.offset) {\n patches.push(set(offset, ['offset']))\n }\n\n props.onChange(patches)\n }\n\n const dateToDisplay = value?.utc ? getConstructedUTCDate(value.utc, value.offset) : ''\n //@ts-expect-error -- slight mismatch in elementProps and renderDefault, but should line up in practice\n return <DateTimeInput {...props} onChange={handleDateChange} value={dateToDisplay} />\n}\n","import {SearchIcon} from '@sanity/icons'\nimport {ObjectInputProps, set} from 'sanity'\nimport {allTimezones, unlocalizeDateTime} from '../utils'\nimport {NormalizedTimeZone, RichDate} from '../types'\nimport {Autocomplete, Card, Text, Box} from '@sanity/ui'\nimport {formatInTimeZone, zonedTimeToUtc} from 'date-fns-tz'\n\ninterface TimezoneSelectorProps {\n onChange: Pick<ObjectInputProps, 'onChange'>['onChange']\n value?: RichDate\n}\n\nexport const TimezoneSelector = (props: TimezoneSelectorProps) => {\n const {onChange, value} = props\n const currentTz = allTimezones.find((tz) => tz.name === value?.timezone)\n const userTzName = Intl.DateTimeFormat().resolvedOptions().timeZone\n const userTz = (allTimezones.find((tz) => tz.name === userTzName) ??\n allTimezones.find((tz) => tz.group.includes(userTzName)))!\n\n const handleTimezoneChange = (selectedTz: string) => {\n const newTimezone =\n allTimezones.find((tz) => tz.value === selectedTz) ?? (userTz as NormalizedTimeZone)\n\n const offset = newTimezone.currentTimeOffsetInMinutes ?? 0\n const timezonePatch = set(newTimezone.name, ['timezone'])\n const offsetPatch = set(offset, ['offset'])\n const patches = [timezonePatch, offsetPatch]\n\n //then, recalculate UTC and local from \"old\" time with the new offset\n if (value?.utc) {\n const desiredDateTime = unlocalizeDateTime(value.utc, value.timezone)\n const newUtcDate = zonedTimeToUtc(desiredDateTime, newTimezone.name).toISOString()\n const newLocalDate = formatInTimeZone(\n newUtcDate,\n newTimezone.name,\n \"yyyy-MM-dd'T'HH:mm:ssXXX\",\n )\n patches.push(set(newUtcDate, ['utc']))\n patches.push(set(newLocalDate, ['local']))\n }\n onChange(patches)\n }\n\n return (\n //taken from Scheduled Publishing, again!\n //https://github.com/sanity-io/sanity-plugin-scheduled-publishing/blob/bb282e3df9a8a73df37fab8ee1fdd0e2430745be/src/components/dialogs/DialogTimeZone.tsx#L100\n <Box padding={4}>\n <Autocomplete\n fontSize={2}\n icon={SearchIcon}\n id=\"timezone\"\n onChange={handleTimezoneChange}\n openButton\n options={allTimezones}\n padding={4}\n placeholder=\"Search for a city or time zone\"\n popover={{\n boundaryElement: document.querySelector('body'),\n constrainSize: true,\n placement: 'bottom-start',\n }}\n renderOption={(option) => {\n return (\n <Card as=\"button\" padding={3}>\n <Text size={1} textOverflow=\"ellipsis\">\n <span>GMT{option.offset}</span>\n <span style={{fontWeight: 500, marginLeft: '1em'}}>{option.alternativeName}</span>\n <span style={{marginLeft: '1em'}}>{option.mainCities}</span>\n </Text>\n </Card>\n )\n }}\n renderValue={(_, option) => {\n if (!option) return ''\n return `${option.alternativeName} (${option.namePretty})`\n }}\n tabIndex={-1}\n value={currentTz?.value ?? userTz.value}\n />\n </Box>\n )\n}\n","import {Button} from '@sanity/ui'\nimport {EarthAmericasIcon} from '@sanity/icons'\nimport {allTimezones} from '../utils'\n\ninterface TimezoneButtonProps {\n onClick: () => void\n timezone: string\n}\n\nexport const TimezoneButton = (props: TimezoneButtonProps) => {\n const {onClick, timezone} = props\n const currentTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone\n\n const label =\n allTimezones.find((tz) => tz.name === timezone)?.abbreviation ??\n allTimezones.find((tz) => tz.name === currentTimezone)?.abbreviation ??\n allTimezones.find((tz) => tz.group.includes(currentTimezone))?.abbreviation\n\n return (\n <Button\n fontSize={1}\n style={{width: '100%'}}\n justify={'flex-start'}\n icon={EarthAmericasIcon}\n mode=\"ghost\"\n onClick={onClick}\n text={`${label}`}\n aria-label=\"Select a timezone\"\n />\n )\n}\n","import {ObjectInputMember, ObjectInputProps} from 'sanity'\nimport {Box, Flex, Dialog} from '@sanity/ui'\nimport {RelativeDateTimePicker} from './RelativeDateTimePicker'\nimport {TimezoneSelector} from './TimezoneSelector'\nimport {useCallback, useState} from 'react'\nimport {TimezoneButton} from './TimezoneButton'\nimport {RichDate} from '../types'\n\nexport const RichDateInput = (props: ObjectInputProps) => {\n const {onChange, value, members, schemaType} = props\n const {options} = schemaType\n const localMember = members.find((member) => member.kind === 'field' && member.name === 'local')\n const timezoneMember = members.find(\n (member) => member.kind === 'field' && member.name === 'timezone',\n )\n const [timezoneSelectorOpen, setTimezoneSelectorOpen] = useState(false)\n const onClose = useCallback(() => setTimezoneSelectorOpen(false), [])\n const onOpen = useCallback(() => setTimezoneSelectorOpen(true), [])\n\n return (\n <>\n <Flex>\n <Box flex={[1, 2, 4]}>\n {localMember && (\n <ObjectInputMember\n {...props}\n member={localMember}\n renderInput={(renderInputProps) => (\n <RelativeDateTimePicker\n {...renderInputProps}\n dateValue={value as RichDate}\n schemaType={{...renderInputProps.schemaType, options}}\n onChange={onChange}\n />\n )}\n />\n )}\n </Box>\n <Box flex={[1]} marginLeft={[2, 2, 3, 4]}>\n {timezoneMember && (\n <ObjectInputMember\n {...props}\n member={timezoneMember}\n renderInput={() => (\n <TimezoneButton onClick={onOpen} timezone={value?.timezone ?? ''} />\n )}\n />\n )}\n </Box>\n </Flex>\n {timezoneSelectorOpen && (\n <Dialog onClose={onClose} header=\"Select a timezone\" id=\"timezone-select\" width={1}>\n <TimezoneSelector onChange={onChange} value={value as RichDate} />\n </Dialog>\n )}\n </>\n )\n}\n","import {\n DatetimeDefinition,\n ObjectDefinition,\n ObjectSchemaType,\n defineField,\n defineType,\n} from 'sanity'\nimport {RichDateInput} from './components/RichDateInput'\n\nconst richDateTypeName = 'richDate' as const\n\nexport type RichDateSchemaType = Omit<ObjectSchemaType, 'options'> & {\n options?: DatetimeDefinition['options']\n}\n\n/**\n * @public\n */\nexport interface RichDateDefinition extends Omit<ObjectDefinition, 'type' | 'fields' | 'options'> {\n type: typeof richDateTypeName\n options?: DatetimeDefinition['options']\n}\n\ndeclare module 'sanity' {\n //allows the custom input to be valid for the schema def\n export interface IntrinsicDefinitions {\n richDate: RichDateDefinition\n }\n}\n\nexport const richDateSchema = defineType({\n name: richDateTypeName,\n title: 'Rich Date',\n type: 'object',\n fields: [\n defineField({\n name: 'local',\n title: 'Local',\n type: 'string',\n }),\n defineField({\n name: 'utc',\n title: 'UTC',\n type: 'string',\n }),\n defineField({\n name: 'timezone',\n title: 'Timezone',\n type: 'string',\n }),\n defineField({\n name: 'offset',\n title: 'Offset',\n type: 'number',\n }),\n ],\n\n components: {\n input: RichDateInput,\n },\n})\n","import {definePlugin} from 'sanity'\nimport {richDateSchema, RichDateDefinition, RichDateSchemaType} from './schema'\nimport {RichDate} from './types'\n\nexport const richDate = definePlugin({\n name: 'v3-rich-date-input',\n schema: {\n types: [richDateSchema],\n },\n})\n\nexport type {RichDateDefinition, RichDateSchemaType, RichDate}\n"],"names":["unlocalizeDateTime","datetime","timezone","formatInTimeZone","getConstructedUTCDate","utc","offset","date","Date","currentOffset","getTimezoneOffset","diff","fakeUTCDate","getTime","toISOString","allTimezones","getTimeZones","map","tz","abbreviation","alternativeName","mainCities","join","name","namePretty","replaceAll","currentTimeFormat","split","value","concat","currentTimeOffsetInMinutes","group","RelativeDateTimePicker","props","_a","_b","dateValue","Intl","DateTimeFormat","resolvedOptions","timeZone","handleDateChange","patch","patches","newDatetime","type","onChange","unset","desiredDateTime","utcDate","zonedTimeToUtc","localDate","push","set","dateToDisplay","DateTimeInput","TimezoneSelector","currentTz","find","userTzName","userTz","includes","handleTimezoneChange","selectedTz","newTimezone","timezonePatch","offsetPatch","newUtcDate","newLocalDate","jsx","Box","padding","children","Autocomplete","fontSize","icon","SearchIcon","id","openButton","options","placeholder","popover","boundaryElement","document","querySelector","constrainSize","placement","renderOption","option","Card","as","jsxs","Text","size","textOverflow","style","fontWeight","marginLeft","renderValue","_","tabIndex","TimezoneButton","_c","_d","_e","onClick","currentTimezone","label","Button","width","justify","EarthAmericasIcon","mode","text","RichDateInput","members","schemaType","localMember","member","kind","timezoneMember","timezoneSelectorOpen","setTimezoneSelectorOpen","useState","onClose","useCallback","onOpen","Fragment","Flex","flex","ObjectInputMember","renderInput","renderInputProps","Dialog","header","richDateTypeName","richDateSchema","defineType","title","fields","defineField","components","input","richDate","definePlugin","schema","types"],"mappings":"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"}
1
+ {"version":3,"file":"index.esm.js","sources":["../src/utils/index.ts","../src/components/RelativeDateTimePicker.tsx","../src/components/TimezoneButton.tsx","../src/components/TimezoneSelector.tsx","../src/components/RichDateInput.tsx","../src/schema.ts","../src/index.ts"],"sourcesContent":["import {getTimeZones} from '@vvo/tzdb'\nimport {formatInTimeZone} from 'date-fns-tz'\n\nimport {NormalizedTimeZone} from '../types'\n\nexport const unlocalizeDateTime = (datetime: string, timezone: string): string => {\n return formatInTimeZone(datetime, timezone, 'yyyy-MM-dd HH:mm:ss')\n}\n\n/* We have to \"fake\" a UTC date to make the datepicker look \"right\"\n * to the user. For example, if someone sets 7:00AM PST, which is 3PM UTC\n * and I am on the east coast, I want to have 12:00PM UTC, which will look like 7:00AM to me\n * In other words, UTC minus 3 hours, or (UTC(my offset - their offset))\n * this is purely cosmetic and should not be saved at all\n */\nexport const getConstructedUTCDate = (utc: string, offset: number): string => {\n const date = new Date(utc)\n const currentOffset = date.getTimezoneOffset() * -1\n const diff = currentOffset - offset\n const fakeUTCDate = new Date(date.getTime() - diff * 60 * 1000)\n return fakeUTCDate.toISOString()\n}\n\n//keep some consistency with scheduled publishing\n//https://github.com/sanity-io/sanity-plugin-scheduled-publishing/blob/bb282e3df9a8a73df37fab8ee1fdd0e2430745be/src/hooks/useTimeZone.tsx#L17\nexport const allTimezones = getTimeZones().map((tz) => {\n return {\n abbreviation: tz.abbreviation,\n alternativeName: tz.alternativeName,\n mainCities: tz.mainCities.join(', '),\n // Main time zone name 'Africa/Dar_es_Salaam'\n name: tz.name,\n // Time zone name with underscores removed\n namePretty: tz.name.replaceAll('_', ' '),\n offset: tz.currentTimeFormat.split(' ')[0],\n // all searchable text - this is transformed before being rendered in `<AutoComplete>`\n value: `${tz.currentTimeFormat} ${tz.abbreviation} ${tz.name}`,\n currentTimeOffsetInMinutes: tz.currentTimeOffsetInMinutes,\n group: tz.group,\n } as NormalizedTimeZone\n})\n","import {formatInTimeZone, getTimezoneOffset, zonedTimeToUtc} from 'date-fns-tz'\nimport {type ReactNode, useCallback} from 'react'\nimport {DateTimeInput, FormPatch, InputProps, PatchEvent, set, unset} from 'sanity'\n\nimport {RichDate} from '../types'\nimport {getConstructedUTCDate, unlocalizeDateTime} from '../utils'\n\ninterface RelativeDateTimePickerProps extends Omit<InputProps, 'renderDefault'> {\n dateValue?: RichDate\n}\nexport const RelativeDateTimePicker = (props: RelativeDateTimePickerProps): ReactNode => {\n const {dateValue: value, onChange} = props\n\n const handleDateChange = useCallback(\n (patch: FormPatch | PatchEvent | FormPatch[]) => {\n const timezone = value?.timezone ?? Intl.DateTimeFormat().resolvedOptions().timeZone\n const newDatetime = (patch as unknown as {value: string})?.value\n if (!newDatetime || !('type' in patch) || patch.type !== 'set') {\n onChange(unset())\n return\n }\n\n /* get what time the user \"meant\" to set without tz info\n * right now, newDatetime is the time the user set plus\n * their current offset, not the timezone offset\n */\n const desiredDateTime = unlocalizeDateTime(\n newDatetime,\n Intl.DateTimeFormat().resolvedOptions().timeZone,\n )\n\n const newUtcDateObject = zonedTimeToUtc(desiredDateTime, timezone)\n // offset may have changed based on DST, capture that\n const newOffset = getTimezoneOffset(timezone, newUtcDateObject) / 60 / 1000\n const localDate = formatInTimeZone(newUtcDateObject, timezone, \"yyyy-MM-dd'T'HH:mm:ssXXX\")\n\n const patches = []\n\n patches.push(set(newUtcDateObject.toISOString(), ['utc']))\n patches.push(set(localDate, ['local']))\n\n if (!value?.timezone) {\n patches.push(set(timezone, ['timezone']))\n }\n\n if (value?.offset !== newOffset) {\n patches.push(set(newOffset, ['offset']))\n }\n\n onChange(patches)\n },\n [onChange, value],\n )\n\n const dateToDisplay = value?.utc ? getConstructedUTCDate(value.utc, value.offset) : ''\n\n // @ts-expect-error -- slight mismatch in elementProps and renderDefault, but should line up in practice\n return <DateTimeInput {...props} onChange={handleDateChange} value={dateToDisplay} />\n}\n","import {EarthAmericasIcon} from '@sanity/icons'\nimport {Button} from '@sanity/ui'\nimport {type ReactNode} from 'react'\n\nimport {allTimezones} from '../utils'\n\ninterface TimezoneButtonProps {\n onClick: () => void\n timezone: string\n}\n\nexport const TimezoneButton = (props: TimezoneButtonProps): ReactNode => {\n const {onClick, timezone} = props\n const currentTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone\n\n const label =\n allTimezones.find((tz) => tz.name === timezone)?.abbreviation ??\n allTimezones.find((tz) => tz.name === currentTimezone)?.abbreviation ??\n allTimezones.find((tz) => tz.group.includes(currentTimezone))?.abbreviation\n\n return (\n <Button\n fontSize={1}\n style={{width: '100%'}}\n justify={'flex-start'}\n icon={EarthAmericasIcon}\n mode=\"ghost\"\n onClick={onClick}\n text={`${label}`}\n aria-label=\"Select a timezone\"\n />\n )\n}\n","import {SearchIcon} from '@sanity/icons'\nimport {Autocomplete, Box, Card, Text} from '@sanity/ui'\nimport {formatInTimeZone, getTimezoneOffset, zonedTimeToUtc} from 'date-fns-tz'\nimport {type ReactNode, useCallback} from 'react'\nimport {ObjectInputProps, set} from 'sanity'\n\nimport {NormalizedTimeZone, RichDate} from '../types'\nimport {allTimezones, unlocalizeDateTime} from '../utils'\n\ninterface TimezoneSelectorProps {\n onChange: Pick<ObjectInputProps, 'onChange'>['onChange']\n value?: RichDate\n}\n\nexport const TimezoneSelector = (props: TimezoneSelectorProps): ReactNode => {\n const {onChange, value} = props\n const currentTz = allTimezones.find((tz) => tz.name === value?.timezone)\n const userTzName = Intl.DateTimeFormat().resolvedOptions().timeZone\n const userTz = (allTimezones.find((tz) => tz.name === userTzName) ??\n allTimezones.find((tz) => tz.group.includes(userTzName)))!\n\n const handleTimezoneChange = useCallback(\n (selectedTz: string) => {\n const newTimezone =\n allTimezones.find((tz) => tz.value === selectedTz) ?? (userTz as NormalizedTimeZone)\n\n const timezonePatch = set(newTimezone.name, ['timezone'])\n const patches = [timezonePatch]\n\n // then, recalculate UTC and local from \"old\" time with the new offset\n if (value?.utc) {\n const desiredDateTime = unlocalizeDateTime(value.utc, value.timezone)\n const newUtcDateObject = zonedTimeToUtc(desiredDateTime, newTimezone.name)\n const newOffset = getTimezoneOffset(newTimezone.name, newUtcDateObject) / 60 / 1000\n const newLocalDate = formatInTimeZone(\n newUtcDateObject.toISOString(),\n newTimezone.name,\n \"yyyy-MM-dd'T'HH:mm:ssXXX\",\n )\n patches.push(set(newUtcDateObject.toISOString(), ['utc']))\n patches.push(set(newLocalDate, ['local']))\n patches.push(set(newOffset, ['offset']))\n }\n onChange(patches)\n },\n [onChange, userTz, value],\n )\n\n return (\n // taken from Scheduled Publishing, again!\n // https://github.com/sanity-io/sanity-plugin-scheduled-publishing/blob/bb282e3df9a8a73df37fab8ee1fdd0e2430745be/src/components/dialogs/DialogTimeZone.tsx#L100\n <Box padding={4}>\n <Autocomplete\n fontSize={2}\n icon={SearchIcon}\n id=\"timezone\"\n onChange={handleTimezoneChange}\n openButton\n options={allTimezones}\n padding={4}\n placeholder=\"Search for a city or time zone\"\n popover={{\n boundaryElement: document.querySelector('body'),\n constrainSize: true,\n placement: 'bottom-start',\n }}\n // eslint-disable-next-line react/jsx-no-bind\n renderOption={(option) => {\n return (\n <Card as=\"button\" padding={3}>\n <Text size={1} textOverflow=\"ellipsis\">\n <span>GMT{option.offset}</span>\n <span style={{fontWeight: 500, marginLeft: '1em'}}>{option.alternativeName}</span>\n <span style={{marginLeft: '1em'}}>{option.mainCities}</span>\n </Text>\n </Card>\n )\n }}\n // eslint-disable-next-line react/jsx-no-bind\n renderValue={(_, option) => {\n if (!option) return ''\n return `${option.alternativeName} (${option.namePretty})`\n }}\n tabIndex={-1}\n value={currentTz?.value ?? userTz.value}\n />\n </Box>\n )\n}\n","import {Box, Dialog, Flex} from '@sanity/ui'\nimport {type ReactNode, useCallback, useState} from 'react'\nimport {ObjectInputMember, ObjectInputProps} from 'sanity'\n\nimport {RichDate} from '../types'\nimport {RelativeDateTimePicker} from './RelativeDateTimePicker'\nimport {TimezoneButton} from './TimezoneButton'\nimport {TimezoneSelector} from './TimezoneSelector'\n\nexport const RichDateInput = (props: ObjectInputProps): ReactNode => {\n const {onChange, value, members, schemaType} = props\n const {options} = schemaType\n const localMember = members.find((member) => member.kind === 'field' && member.name === 'local')\n const timezoneMember = members.find(\n (member) => member.kind === 'field' && member.name === 'timezone',\n )\n const [timezoneSelectorOpen, setTimezoneSelectorOpen] = useState(false)\n const onClose = useCallback(() => setTimezoneSelectorOpen(false), [])\n const onOpen = useCallback(() => setTimezoneSelectorOpen(true), [])\n\n return (\n <>\n <Flex>\n <Box flex={[1, 2, 4]}>\n {localMember && (\n <ObjectInputMember\n {...props}\n member={localMember}\n // eslint-disable-next-line react/jsx-no-bind\n renderInput={(renderInputProps) => (\n <RelativeDateTimePicker\n {...renderInputProps}\n dateValue={value as RichDate}\n schemaType={{...renderInputProps.schemaType, options}}\n onChange={onChange}\n />\n )}\n />\n )}\n </Box>\n <Box flex={[1]} marginLeft={[2, 2, 3, 4]}>\n {timezoneMember && (\n <ObjectInputMember\n {...props}\n member={timezoneMember}\n // eslint-disable-next-line react/jsx-no-bind\n renderInput={() => (\n <TimezoneButton onClick={onOpen} timezone={value?.timezone ?? ''} />\n )}\n />\n )}\n </Box>\n </Flex>\n {timezoneSelectorOpen && (\n <Dialog onClose={onClose} header=\"Select a timezone\" id=\"timezone-select\" width={1}>\n <TimezoneSelector onChange={onChange} value={value as RichDate} />\n </Dialog>\n )}\n </>\n )\n}\n","import {\n DatetimeDefinition,\n defineField,\n defineType,\n ObjectDefinition,\n ObjectSchemaType,\n} from 'sanity'\n\nimport {RichDateInput} from './components/RichDateInput'\n\nconst richDateTypeName = 'richDate' as const\n\nexport type RichDateSchemaType = Omit<ObjectSchemaType, 'options'> & {\n options?: DatetimeDefinition['options']\n}\n\n/**\n * @public\n */\nexport interface RichDateDefinition extends Omit<ObjectDefinition, 'type' | 'fields' | 'options'> {\n type: typeof richDateTypeName\n options?: DatetimeDefinition['options']\n}\n\ndeclare module 'sanity' {\n //allows the custom input to be valid for the schema def\n export interface IntrinsicDefinitions {\n richDate: RichDateDefinition\n }\n}\n\nexport const richDateSchema = defineType({\n name: richDateTypeName,\n title: 'Rich Date',\n type: 'object',\n fields: [\n defineField({\n name: 'local',\n title: 'Local',\n type: 'string',\n }),\n defineField({\n name: 'utc',\n title: 'UTC',\n type: 'string',\n }),\n defineField({\n name: 'timezone',\n title: 'Timezone',\n type: 'string',\n }),\n defineField({\n name: 'offset',\n title: 'Offset',\n type: 'number',\n }),\n ],\n\n components: {\n input: RichDateInput,\n },\n})\n","import {definePlugin} from 'sanity'\n\nimport {RichDateDefinition, richDateSchema, RichDateSchemaType} from './schema'\nimport {RichDate} from './types'\n\nexport const richDate = definePlugin({\n name: 'v3-rich-date-input',\n schema: {\n types: [richDateSchema],\n },\n})\n\nexport type {RichDate, RichDateDefinition, RichDateSchemaType}\n"],"names":["unlocalizeDateTime","datetime","timezone","formatInTimeZone","getConstructedUTCDate","utc","offset","date","Date","currentOffset","getTimezoneOffset","diff","fakeUTCDate","getTime","toISOString","allTimezones","getTimeZones","map","tz","abbreviation","alternativeName","mainCities","join","name","namePretty","replaceAll","currentTimeFormat","split","value","concat","currentTimeOffsetInMinutes","group","RelativeDateTimePicker","props","dateValue","onChange","handleDateChange","useCallback","patch","_a","Intl","DateTimeFormat","resolvedOptions","timeZone","newDatetime","type","unset","desiredDateTime","newUtcDateObject","zonedTimeToUtc","newOffset","localDate","patches","push","set","dateToDisplay","DateTimeInput","TimezoneButton","_b","_c","_d","_e","onClick","currentTimezone","label","find","includes","jsx","Button","fontSize","style","width","justify","icon","EarthAmericasIcon","mode","text","TimezoneSelector","currentTz","userTzName","userTz","handleTimezoneChange","selectedTz","newTimezone","timezonePatch","newLocalDate","Box","padding","children","Autocomplete","SearchIcon","id","openButton","options","placeholder","popover","boundaryElement","document","querySelector","constrainSize","placement","renderOption","option","Card","as","jsxs","Text","size","textOverflow","fontWeight","marginLeft","renderValue","_","tabIndex","RichDateInput","members","schemaType","localMember","member","kind","timezoneMember","timezoneSelectorOpen","setTimezoneSelectorOpen","useState","onClose","onOpen","Fragment","Flex","flex","ObjectInputMember","renderInput","renderInputProps","Dialog","header","richDateTypeName","richDateSchema","defineType","title","fields","defineField","components","input","richDate","definePlugin","schema","types"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -6,16 +6,16 @@ Object.defineProperty(exports, '__esModule', {
6
6
  var sanity = require('sanity');
7
7
  var jsxRuntime = require('react/jsx-runtime');
8
8
  var ui = require('@sanity/ui');
9
- var tzdb = require('@vvo/tzdb');
9
+ var react = require('react');
10
10
  var dateFnsTz = require('date-fns-tz');
11
+ var tzdb = require('@vvo/tzdb');
11
12
  var icons = require('@sanity/icons');
12
- var react = require('react');
13
13
  const unlocalizeDateTime = (datetime, timezone) => {
14
14
  return dateFnsTz.formatInTimeZone(datetime, timezone, "yyyy-MM-dd HH:mm:ss");
15
15
  };
16
16
  const getConstructedUTCDate = (utc, offset) => {
17
17
  const date = new Date(utc);
18
- const currentOffset = ( /* @__PURE__ */new Date()).getTimezoneOffset() * -1;
18
+ const currentOffset = date.getTimezoneOffset() * -1;
19
19
  const diff = currentOffset - offset;
20
20
  const fakeUTCDate = new Date(date.getTime() - diff * 60 * 1e3);
21
21
  return fakeUTCDate.toISOString();
@@ -37,30 +37,33 @@ const allTimezones = tzdb.getTimeZones().map(tz => {
37
37
  };
38
38
  });
39
39
  const RelativeDateTimePicker = props => {
40
- var _a, _b;
41
- const value = props.dateValue;
42
- const timezone = (_a = value == null ? void 0 : value.timezone) != null ? _a : Intl.DateTimeFormat().resolvedOptions().timeZone;
43
- const offset = (_b = value == null ? void 0 : value.offset) != null ? _b : ( /* @__PURE__ */new Date()).getTimezoneOffset() * -1;
44
- const handleDateChange = patch => {
45
- const patches = [];
40
+ const {
41
+ dateValue: value,
42
+ onChange
43
+ } = props;
44
+ const handleDateChange = react.useCallback(patch => {
45
+ var _a;
46
+ const timezone = (_a = value == null ? void 0 : value.timezone) != null ? _a : Intl.DateTimeFormat().resolvedOptions().timeZone;
46
47
  const newDatetime = patch == null ? void 0 : patch.value;
47
48
  if (!newDatetime || !("type" in patch) || patch.type !== "set") {
48
- props.onChange(sanity.unset());
49
+ onChange(sanity.unset());
49
50
  return;
50
51
  }
51
52
  const desiredDateTime = unlocalizeDateTime(newDatetime, Intl.DateTimeFormat().resolvedOptions().timeZone);
52
- const utcDate = dateFnsTz.zonedTimeToUtc(desiredDateTime, timezone).toISOString();
53
- const localDate = dateFnsTz.formatInTimeZone(utcDate, timezone, "yyyy-MM-dd'T'HH:mm:ssXXX");
54
- patches.push(sanity.set(utcDate, ["utc"]));
53
+ const newUtcDateObject = dateFnsTz.zonedTimeToUtc(desiredDateTime, timezone);
54
+ const newOffset = dateFnsTz.getTimezoneOffset(timezone, newUtcDateObject) / 60 / 1e3;
55
+ const localDate = dateFnsTz.formatInTimeZone(newUtcDateObject, timezone, "yyyy-MM-dd'T'HH:mm:ssXXX");
56
+ const patches = [];
57
+ patches.push(sanity.set(newUtcDateObject.toISOString(), ["utc"]));
55
58
  patches.push(sanity.set(localDate, ["local"]));
56
59
  if (!(value == null ? void 0 : value.timezone)) {
57
60
  patches.push(sanity.set(timezone, ["timezone"]));
58
61
  }
59
- if (!(value == null ? void 0 : value.offset)) {
60
- patches.push(sanity.set(offset, ["offset"]));
62
+ if ((value == null ? void 0 : value.offset) !== newOffset) {
63
+ patches.push(sanity.set(newOffset, ["offset"]));
61
64
  }
62
- props.onChange(patches);
63
- };
65
+ onChange(patches);
66
+ }, [onChange, value]);
64
67
  const dateToDisplay = (value == null ? void 0 : value.utc) ? getConstructedUTCDate(value.utc, value.offset) : "";
65
68
  return /* @__PURE__ */jsxRuntime.jsx(sanity.DateTimeInput, {
66
69
  ...props,
@@ -68,6 +71,27 @@ const RelativeDateTimePicker = props => {
68
71
  value: dateToDisplay
69
72
  });
70
73
  };
74
+ const TimezoneButton = props => {
75
+ var _a, _b, _c, _d, _e;
76
+ const {
77
+ onClick,
78
+ timezone
79
+ } = props;
80
+ const currentTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
81
+ const label = (_e = (_c = (_a = allTimezones.find(tz => tz.name === timezone)) == null ? void 0 : _a.abbreviation) != null ? _c : (_b = allTimezones.find(tz => tz.name === currentTimezone)) == null ? void 0 : _b.abbreviation) != null ? _e : (_d = allTimezones.find(tz => tz.group.includes(currentTimezone))) == null ? void 0 : _d.abbreviation;
82
+ return /* @__PURE__ */jsxRuntime.jsx(ui.Button, {
83
+ fontSize: 1,
84
+ style: {
85
+ width: "100%"
86
+ },
87
+ justify: "flex-start",
88
+ icon: icons.EarthAmericasIcon,
89
+ mode: "ghost",
90
+ onClick,
91
+ text: "".concat(label),
92
+ "aria-label": "Select a timezone"
93
+ });
94
+ };
71
95
  const TimezoneSelector = props => {
72
96
  var _a, _b;
73
97
  const {
@@ -77,25 +101,25 @@ const TimezoneSelector = props => {
77
101
  const currentTz = allTimezones.find(tz => tz.name === (value == null ? void 0 : value.timezone));
78
102
  const userTzName = Intl.DateTimeFormat().resolvedOptions().timeZone;
79
103
  const userTz = (_a = allTimezones.find(tz => tz.name === userTzName)) != null ? _a : allTimezones.find(tz => tz.group.includes(userTzName));
80
- const handleTimezoneChange = selectedTz => {
81
- var _a2, _b2;
104
+ const handleTimezoneChange = react.useCallback(selectedTz => {
105
+ var _a2;
82
106
  const newTimezone = (_a2 = allTimezones.find(tz => tz.value === selectedTz)) != null ? _a2 : userTz;
83
- const offset = (_b2 = newTimezone.currentTimeOffsetInMinutes) != null ? _b2 : 0;
84
107
  const timezonePatch = sanity.set(newTimezone.name, ["timezone"]);
85
- const offsetPatch = sanity.set(offset, ["offset"]);
86
- const patches = [timezonePatch, offsetPatch];
108
+ const patches = [timezonePatch];
87
109
  if (value == null ? void 0 : value.utc) {
88
110
  const desiredDateTime = unlocalizeDateTime(value.utc, value.timezone);
89
- const newUtcDate = dateFnsTz.zonedTimeToUtc(desiredDateTime, newTimezone.name).toISOString();
90
- const newLocalDate = dateFnsTz.formatInTimeZone(newUtcDate, newTimezone.name, "yyyy-MM-dd'T'HH:mm:ssXXX");
91
- patches.push(sanity.set(newUtcDate, ["utc"]));
111
+ const newUtcDateObject = dateFnsTz.zonedTimeToUtc(desiredDateTime, newTimezone.name);
112
+ const newOffset = dateFnsTz.getTimezoneOffset(newTimezone.name, newUtcDateObject) / 60 / 1e3;
113
+ const newLocalDate = dateFnsTz.formatInTimeZone(newUtcDateObject.toISOString(), newTimezone.name, "yyyy-MM-dd'T'HH:mm:ssXXX");
114
+ patches.push(sanity.set(newUtcDateObject.toISOString(), ["utc"]));
92
115
  patches.push(sanity.set(newLocalDate, ["local"]));
116
+ patches.push(sanity.set(newOffset, ["offset"]));
93
117
  }
94
118
  onChange(patches);
95
- };
119
+ }, [onChange, userTz, value]);
96
120
  return (
97
- //taken from Scheduled Publishing, again!
98
- //https://github.com/sanity-io/sanity-plugin-scheduled-publishing/blob/bb282e3df9a8a73df37fab8ee1fdd0e2430745be/src/components/dialogs/DialogTimeZone.tsx#L100
121
+ // taken from Scheduled Publishing, again!
122
+ // https://github.com/sanity-io/sanity-plugin-scheduled-publishing/blob/bb282e3df9a8a73df37fab8ee1fdd0e2430745be/src/components/dialogs/DialogTimeZone.tsx#L100
99
123
  /* @__PURE__ */
100
124
  jsxRuntime.jsx(ui.Box, {
101
125
  padding: 4,
@@ -147,27 +171,6 @@ const TimezoneSelector = props => {
147
171
  })
148
172
  );
149
173
  };
150
- const TimezoneButton = props => {
151
- var _a, _b, _c, _d, _e;
152
- const {
153
- onClick,
154
- timezone
155
- } = props;
156
- const currentTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
157
- const label = (_e = (_c = (_a = allTimezones.find(tz => tz.name === timezone)) == null ? void 0 : _a.abbreviation) != null ? _c : (_b = allTimezones.find(tz => tz.name === currentTimezone)) == null ? void 0 : _b.abbreviation) != null ? _e : (_d = allTimezones.find(tz => tz.group.includes(currentTimezone))) == null ? void 0 : _d.abbreviation;
158
- return /* @__PURE__ */jsxRuntime.jsx(ui.Button, {
159
- fontSize: 1,
160
- style: {
161
- width: "100%"
162
- },
163
- justify: "flex-start",
164
- icon: icons.EarthAmericasIcon,
165
- mode: "ghost",
166
- onClick,
167
- text: "".concat(label),
168
- "aria-label": "Select a timezone"
169
- });
170
- };
171
174
  const RichDateInput = props => {
172
175
  const {
173
176
  onChange,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/utils/index.ts","../src/components/RelativeDateTimePicker.tsx","../src/components/TimezoneSelector.tsx","../src/components/TimezoneButton.tsx","../src/components/RichDateInput.tsx","../src/schema.ts","../src/index.ts"],"sourcesContent":["import {getTimeZones} from '@vvo/tzdb'\nimport {NormalizedTimeZone} from '../types'\nimport {formatInTimeZone} from 'date-fns-tz'\n\nexport const unlocalizeDateTime = (datetime: string, timezone: string): string => {\n return formatInTimeZone(datetime, timezone, 'yyyy-MM-dd HH:mm:ss')\n}\n\n/* We have to \"fake\" a UTC date to make the datepicker look \"right\"\n * to the user. For example, if someone sets 7:00AM PST, which is 3PM UTC\n * and I am on the east coast, I want to have 12:00PM UTC, which will look like 7:00AM to me\n * In other words, UTC minus 3 hours, or (UTC(my offset - their offset))\n * this is purely cosmetic and should not be saved at all\n */\nexport const getConstructedUTCDate = (utc: string, offset: number): string => {\n const date = new Date(utc)\n const currentOffset = new Date().getTimezoneOffset() * -1\n const diff = currentOffset - offset\n const fakeUTCDate = new Date(date.getTime() - diff * 60 * 1000)\n return fakeUTCDate.toISOString()\n}\n\n//keep some consistency with scheduled publishing\n//https://github.com/sanity-io/sanity-plugin-scheduled-publishing/blob/bb282e3df9a8a73df37fab8ee1fdd0e2430745be/src/hooks/useTimeZone.tsx#L17\nexport const allTimezones = getTimeZones().map((tz) => {\n return {\n abbreviation: tz.abbreviation,\n alternativeName: tz.alternativeName,\n mainCities: tz.mainCities.join(', '),\n // Main time zone name 'Africa/Dar_es_Salaam'\n name: tz.name,\n // Time zone name with underscores removed\n namePretty: tz.name.replaceAll('_', ' '),\n offset: tz.currentTimeFormat.split(' ')[0],\n // all searchable text - this is transformed before being rendered in `<AutoComplete>`\n value: `${tz.currentTimeFormat} ${tz.abbreviation} ${tz.name}`,\n currentTimeOffsetInMinutes: tz.currentTimeOffsetInMinutes,\n group: tz.group,\n } as NormalizedTimeZone\n})\n","import {DateTimeInput, FormPatch, PatchEvent, InputProps, set, unset} from 'sanity'\n\nimport {getConstructedUTCDate, unlocalizeDateTime} from '../utils'\nimport {RichDate} from '../types'\nimport {formatInTimeZone, zonedTimeToUtc} from 'date-fns-tz'\n\ninterface RelativeDateTimePickerProps extends Omit<InputProps, 'renderDefault'> {\n dateValue?: RichDate\n}\n\nexport const RelativeDateTimePicker = (props: RelativeDateTimePickerProps) => {\n const value = props.dateValue\n const timezone = value?.timezone ?? Intl.DateTimeFormat().resolvedOptions().timeZone\n /*\n * if our offset is not coming from a lib, we have to reverse it\n * to get the real offset used everywhere\n * https://momentjscom.readthedocs.io/en/latest/moment/03-manipulating/09-utc-offset/\n */\n const offset = value?.offset ?? new Date().getTimezoneOffset() * -1\n const handleDateChange = (patch: FormPatch | PatchEvent | FormPatch[]) => {\n const patches = []\n const newDatetime = (patch as unknown as {value: string})?.value\n if (!newDatetime || !('type' in patch) || patch.type !== 'set') {\n props.onChange(unset())\n return\n }\n\n //get what time the user \"meant\" to set without tz info\n //since the datepicker always localizes to the user's timezone\n const desiredDateTime = unlocalizeDateTime(\n newDatetime,\n Intl.DateTimeFormat().resolvedOptions().timeZone,\n )\n\n //use the user-selected timezone here\n const utcDate = zonedTimeToUtc(desiredDateTime, timezone).toISOString()\n const localDate = formatInTimeZone(utcDate, timezone, \"yyyy-MM-dd'T'HH:mm:ssXXX\")\n\n patches.push(set(utcDate, ['utc']))\n patches.push(set(localDate, ['local']))\n\n if (!value?.timezone) {\n patches.push(set(timezone, ['timezone']))\n }\n\n if (!value?.offset) {\n patches.push(set(offset, ['offset']))\n }\n\n props.onChange(patches)\n }\n\n const dateToDisplay = value?.utc ? getConstructedUTCDate(value.utc, value.offset) : ''\n //@ts-expect-error -- slight mismatch in elementProps and renderDefault, but should line up in practice\n return <DateTimeInput {...props} onChange={handleDateChange} value={dateToDisplay} />\n}\n","import {SearchIcon} from '@sanity/icons'\nimport {ObjectInputProps, set} from 'sanity'\nimport {allTimezones, unlocalizeDateTime} from '../utils'\nimport {NormalizedTimeZone, RichDate} from '../types'\nimport {Autocomplete, Card, Text, Box} from '@sanity/ui'\nimport {formatInTimeZone, zonedTimeToUtc} from 'date-fns-tz'\n\ninterface TimezoneSelectorProps {\n onChange: Pick<ObjectInputProps, 'onChange'>['onChange']\n value?: RichDate\n}\n\nexport const TimezoneSelector = (props: TimezoneSelectorProps) => {\n const {onChange, value} = props\n const currentTz = allTimezones.find((tz) => tz.name === value?.timezone)\n const userTzName = Intl.DateTimeFormat().resolvedOptions().timeZone\n const userTz = (allTimezones.find((tz) => tz.name === userTzName) ??\n allTimezones.find((tz) => tz.group.includes(userTzName)))!\n\n const handleTimezoneChange = (selectedTz: string) => {\n const newTimezone =\n allTimezones.find((tz) => tz.value === selectedTz) ?? (userTz as NormalizedTimeZone)\n\n const offset = newTimezone.currentTimeOffsetInMinutes ?? 0\n const timezonePatch = set(newTimezone.name, ['timezone'])\n const offsetPatch = set(offset, ['offset'])\n const patches = [timezonePatch, offsetPatch]\n\n //then, recalculate UTC and local from \"old\" time with the new offset\n if (value?.utc) {\n const desiredDateTime = unlocalizeDateTime(value.utc, value.timezone)\n const newUtcDate = zonedTimeToUtc(desiredDateTime, newTimezone.name).toISOString()\n const newLocalDate = formatInTimeZone(\n newUtcDate,\n newTimezone.name,\n \"yyyy-MM-dd'T'HH:mm:ssXXX\",\n )\n patches.push(set(newUtcDate, ['utc']))\n patches.push(set(newLocalDate, ['local']))\n }\n onChange(patches)\n }\n\n return (\n //taken from Scheduled Publishing, again!\n //https://github.com/sanity-io/sanity-plugin-scheduled-publishing/blob/bb282e3df9a8a73df37fab8ee1fdd0e2430745be/src/components/dialogs/DialogTimeZone.tsx#L100\n <Box padding={4}>\n <Autocomplete\n fontSize={2}\n icon={SearchIcon}\n id=\"timezone\"\n onChange={handleTimezoneChange}\n openButton\n options={allTimezones}\n padding={4}\n placeholder=\"Search for a city or time zone\"\n popover={{\n boundaryElement: document.querySelector('body'),\n constrainSize: true,\n placement: 'bottom-start',\n }}\n renderOption={(option) => {\n return (\n <Card as=\"button\" padding={3}>\n <Text size={1} textOverflow=\"ellipsis\">\n <span>GMT{option.offset}</span>\n <span style={{fontWeight: 500, marginLeft: '1em'}}>{option.alternativeName}</span>\n <span style={{marginLeft: '1em'}}>{option.mainCities}</span>\n </Text>\n </Card>\n )\n }}\n renderValue={(_, option) => {\n if (!option) return ''\n return `${option.alternativeName} (${option.namePretty})`\n }}\n tabIndex={-1}\n value={currentTz?.value ?? userTz.value}\n />\n </Box>\n )\n}\n","import {Button} from '@sanity/ui'\nimport {EarthAmericasIcon} from '@sanity/icons'\nimport {allTimezones} from '../utils'\n\ninterface TimezoneButtonProps {\n onClick: () => void\n timezone: string\n}\n\nexport const TimezoneButton = (props: TimezoneButtonProps) => {\n const {onClick, timezone} = props\n const currentTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone\n\n const label =\n allTimezones.find((tz) => tz.name === timezone)?.abbreviation ??\n allTimezones.find((tz) => tz.name === currentTimezone)?.abbreviation ??\n allTimezones.find((tz) => tz.group.includes(currentTimezone))?.abbreviation\n\n return (\n <Button\n fontSize={1}\n style={{width: '100%'}}\n justify={'flex-start'}\n icon={EarthAmericasIcon}\n mode=\"ghost\"\n onClick={onClick}\n text={`${label}`}\n aria-label=\"Select a timezone\"\n />\n )\n}\n","import {ObjectInputMember, ObjectInputProps} from 'sanity'\nimport {Box, Flex, Dialog} from '@sanity/ui'\nimport {RelativeDateTimePicker} from './RelativeDateTimePicker'\nimport {TimezoneSelector} from './TimezoneSelector'\nimport {useCallback, useState} from 'react'\nimport {TimezoneButton} from './TimezoneButton'\nimport {RichDate} from '../types'\n\nexport const RichDateInput = (props: ObjectInputProps) => {\n const {onChange, value, members, schemaType} = props\n const {options} = schemaType\n const localMember = members.find((member) => member.kind === 'field' && member.name === 'local')\n const timezoneMember = members.find(\n (member) => member.kind === 'field' && member.name === 'timezone',\n )\n const [timezoneSelectorOpen, setTimezoneSelectorOpen] = useState(false)\n const onClose = useCallback(() => setTimezoneSelectorOpen(false), [])\n const onOpen = useCallback(() => setTimezoneSelectorOpen(true), [])\n\n return (\n <>\n <Flex>\n <Box flex={[1, 2, 4]}>\n {localMember && (\n <ObjectInputMember\n {...props}\n member={localMember}\n renderInput={(renderInputProps) => (\n <RelativeDateTimePicker\n {...renderInputProps}\n dateValue={value as RichDate}\n schemaType={{...renderInputProps.schemaType, options}}\n onChange={onChange}\n />\n )}\n />\n )}\n </Box>\n <Box flex={[1]} marginLeft={[2, 2, 3, 4]}>\n {timezoneMember && (\n <ObjectInputMember\n {...props}\n member={timezoneMember}\n renderInput={() => (\n <TimezoneButton onClick={onOpen} timezone={value?.timezone ?? ''} />\n )}\n />\n )}\n </Box>\n </Flex>\n {timezoneSelectorOpen && (\n <Dialog onClose={onClose} header=\"Select a timezone\" id=\"timezone-select\" width={1}>\n <TimezoneSelector onChange={onChange} value={value as RichDate} />\n </Dialog>\n )}\n </>\n )\n}\n","import {\n DatetimeDefinition,\n ObjectDefinition,\n ObjectSchemaType,\n defineField,\n defineType,\n} from 'sanity'\nimport {RichDateInput} from './components/RichDateInput'\n\nconst richDateTypeName = 'richDate' as const\n\nexport type RichDateSchemaType = Omit<ObjectSchemaType, 'options'> & {\n options?: DatetimeDefinition['options']\n}\n\n/**\n * @public\n */\nexport interface RichDateDefinition extends Omit<ObjectDefinition, 'type' | 'fields' | 'options'> {\n type: typeof richDateTypeName\n options?: DatetimeDefinition['options']\n}\n\ndeclare module 'sanity' {\n //allows the custom input to be valid for the schema def\n export interface IntrinsicDefinitions {\n richDate: RichDateDefinition\n }\n}\n\nexport const richDateSchema = defineType({\n name: richDateTypeName,\n title: 'Rich Date',\n type: 'object',\n fields: [\n defineField({\n name: 'local',\n title: 'Local',\n type: 'string',\n }),\n defineField({\n name: 'utc',\n title: 'UTC',\n type: 'string',\n }),\n defineField({\n name: 'timezone',\n title: 'Timezone',\n type: 'string',\n }),\n defineField({\n name: 'offset',\n title: 'Offset',\n type: 'number',\n }),\n ],\n\n components: {\n input: RichDateInput,\n },\n})\n","import {definePlugin} from 'sanity'\nimport {richDateSchema, RichDateDefinition, RichDateSchemaType} from './schema'\nimport {RichDate} from './types'\n\nexport const richDate = definePlugin({\n name: 'v3-rich-date-input',\n schema: {\n types: [richDateSchema],\n },\n})\n\nexport type {RichDateDefinition, RichDateSchemaType, RichDate}\n"],"names":["unlocalizeDateTime","datetime","timezone","formatInTimeZone","getConstructedUTCDate","utc","offset","date","Date","currentOffset","getTimezoneOffset","diff","fakeUTCDate","getTime","toISOString","allTimezones","getTimeZones","map","tz","abbreviation","alternativeName","mainCities","join","name","namePretty","replaceAll","currentTimeFormat","split","value","concat","currentTimeOffsetInMinutes","group","RelativeDateTimePicker","props","_a","_b","dateValue","Intl","DateTimeFormat","resolvedOptions","timeZone","handleDateChange","patch","patches","newDatetime","type","onChange","unset","desiredDateTime","utcDate","zonedTimeToUtc","localDate","push","set","dateToDisplay","DateTimeInput","TimezoneSelector","currentTz","find","userTzName","userTz","includes","handleTimezoneChange","selectedTz","newTimezone","timezonePatch","offsetPatch","newUtcDate","newLocalDate","jsx","Box","padding","children","Autocomplete","fontSize","icon","SearchIcon","id","openButton","options","placeholder","popover","boundaryElement","document","querySelector","constrainSize","placement","renderOption","option","Card","as","jsxs","Text","size","textOverflow","style","fontWeight","marginLeft","renderValue","_","tabIndex","TimezoneButton","_c","_d","_e","onClick","currentTimezone","label","Button","width","justify","EarthAmericasIcon","mode","text","RichDateInput","members","schemaType","localMember","member","kind","timezoneMember","timezoneSelectorOpen","setTimezoneSelectorOpen","useState","onClose","useCallback","onOpen","Fragment","Flex","flex","ObjectInputMember","renderInput","renderInputProps","Dialog","header","richDateTypeName","richDateSchema","defineType","title","fields","defineField","components","input","richDate","definePlugin","schema","types"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/utils/index.ts","../src/components/RelativeDateTimePicker.tsx","../src/components/TimezoneButton.tsx","../src/components/TimezoneSelector.tsx","../src/components/RichDateInput.tsx","../src/schema.ts","../src/index.ts"],"sourcesContent":["import {getTimeZones} from '@vvo/tzdb'\nimport {formatInTimeZone} from 'date-fns-tz'\n\nimport {NormalizedTimeZone} from '../types'\n\nexport const unlocalizeDateTime = (datetime: string, timezone: string): string => {\n return formatInTimeZone(datetime, timezone, 'yyyy-MM-dd HH:mm:ss')\n}\n\n/* We have to \"fake\" a UTC date to make the datepicker look \"right\"\n * to the user. For example, if someone sets 7:00AM PST, which is 3PM UTC\n * and I am on the east coast, I want to have 12:00PM UTC, which will look like 7:00AM to me\n * In other words, UTC minus 3 hours, or (UTC(my offset - their offset))\n * this is purely cosmetic and should not be saved at all\n */\nexport const getConstructedUTCDate = (utc: string, offset: number): string => {\n const date = new Date(utc)\n const currentOffset = date.getTimezoneOffset() * -1\n const diff = currentOffset - offset\n const fakeUTCDate = new Date(date.getTime() - diff * 60 * 1000)\n return fakeUTCDate.toISOString()\n}\n\n//keep some consistency with scheduled publishing\n//https://github.com/sanity-io/sanity-plugin-scheduled-publishing/blob/bb282e3df9a8a73df37fab8ee1fdd0e2430745be/src/hooks/useTimeZone.tsx#L17\nexport const allTimezones = getTimeZones().map((tz) => {\n return {\n abbreviation: tz.abbreviation,\n alternativeName: tz.alternativeName,\n mainCities: tz.mainCities.join(', '),\n // Main time zone name 'Africa/Dar_es_Salaam'\n name: tz.name,\n // Time zone name with underscores removed\n namePretty: tz.name.replaceAll('_', ' '),\n offset: tz.currentTimeFormat.split(' ')[0],\n // all searchable text - this is transformed before being rendered in `<AutoComplete>`\n value: `${tz.currentTimeFormat} ${tz.abbreviation} ${tz.name}`,\n currentTimeOffsetInMinutes: tz.currentTimeOffsetInMinutes,\n group: tz.group,\n } as NormalizedTimeZone\n})\n","import {formatInTimeZone, getTimezoneOffset, zonedTimeToUtc} from 'date-fns-tz'\nimport {type ReactNode, useCallback} from 'react'\nimport {DateTimeInput, FormPatch, InputProps, PatchEvent, set, unset} from 'sanity'\n\nimport {RichDate} from '../types'\nimport {getConstructedUTCDate, unlocalizeDateTime} from '../utils'\n\ninterface RelativeDateTimePickerProps extends Omit<InputProps, 'renderDefault'> {\n dateValue?: RichDate\n}\nexport const RelativeDateTimePicker = (props: RelativeDateTimePickerProps): ReactNode => {\n const {dateValue: value, onChange} = props\n\n const handleDateChange = useCallback(\n (patch: FormPatch | PatchEvent | FormPatch[]) => {\n const timezone = value?.timezone ?? Intl.DateTimeFormat().resolvedOptions().timeZone\n const newDatetime = (patch as unknown as {value: string})?.value\n if (!newDatetime || !('type' in patch) || patch.type !== 'set') {\n onChange(unset())\n return\n }\n\n /* get what time the user \"meant\" to set without tz info\n * right now, newDatetime is the time the user set plus\n * their current offset, not the timezone offset\n */\n const desiredDateTime = unlocalizeDateTime(\n newDatetime,\n Intl.DateTimeFormat().resolvedOptions().timeZone,\n )\n\n const newUtcDateObject = zonedTimeToUtc(desiredDateTime, timezone)\n // offset may have changed based on DST, capture that\n const newOffset = getTimezoneOffset(timezone, newUtcDateObject) / 60 / 1000\n const localDate = formatInTimeZone(newUtcDateObject, timezone, \"yyyy-MM-dd'T'HH:mm:ssXXX\")\n\n const patches = []\n\n patches.push(set(newUtcDateObject.toISOString(), ['utc']))\n patches.push(set(localDate, ['local']))\n\n if (!value?.timezone) {\n patches.push(set(timezone, ['timezone']))\n }\n\n if (value?.offset !== newOffset) {\n patches.push(set(newOffset, ['offset']))\n }\n\n onChange(patches)\n },\n [onChange, value],\n )\n\n const dateToDisplay = value?.utc ? getConstructedUTCDate(value.utc, value.offset) : ''\n\n // @ts-expect-error -- slight mismatch in elementProps and renderDefault, but should line up in practice\n return <DateTimeInput {...props} onChange={handleDateChange} value={dateToDisplay} />\n}\n","import {EarthAmericasIcon} from '@sanity/icons'\nimport {Button} from '@sanity/ui'\nimport {type ReactNode} from 'react'\n\nimport {allTimezones} from '../utils'\n\ninterface TimezoneButtonProps {\n onClick: () => void\n timezone: string\n}\n\nexport const TimezoneButton = (props: TimezoneButtonProps): ReactNode => {\n const {onClick, timezone} = props\n const currentTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone\n\n const label =\n allTimezones.find((tz) => tz.name === timezone)?.abbreviation ??\n allTimezones.find((tz) => tz.name === currentTimezone)?.abbreviation ??\n allTimezones.find((tz) => tz.group.includes(currentTimezone))?.abbreviation\n\n return (\n <Button\n fontSize={1}\n style={{width: '100%'}}\n justify={'flex-start'}\n icon={EarthAmericasIcon}\n mode=\"ghost\"\n onClick={onClick}\n text={`${label}`}\n aria-label=\"Select a timezone\"\n />\n )\n}\n","import {SearchIcon} from '@sanity/icons'\nimport {Autocomplete, Box, Card, Text} from '@sanity/ui'\nimport {formatInTimeZone, getTimezoneOffset, zonedTimeToUtc} from 'date-fns-tz'\nimport {type ReactNode, useCallback} from 'react'\nimport {ObjectInputProps, set} from 'sanity'\n\nimport {NormalizedTimeZone, RichDate} from '../types'\nimport {allTimezones, unlocalizeDateTime} from '../utils'\n\ninterface TimezoneSelectorProps {\n onChange: Pick<ObjectInputProps, 'onChange'>['onChange']\n value?: RichDate\n}\n\nexport const TimezoneSelector = (props: TimezoneSelectorProps): ReactNode => {\n const {onChange, value} = props\n const currentTz = allTimezones.find((tz) => tz.name === value?.timezone)\n const userTzName = Intl.DateTimeFormat().resolvedOptions().timeZone\n const userTz = (allTimezones.find((tz) => tz.name === userTzName) ??\n allTimezones.find((tz) => tz.group.includes(userTzName)))!\n\n const handleTimezoneChange = useCallback(\n (selectedTz: string) => {\n const newTimezone =\n allTimezones.find((tz) => tz.value === selectedTz) ?? (userTz as NormalizedTimeZone)\n\n const timezonePatch = set(newTimezone.name, ['timezone'])\n const patches = [timezonePatch]\n\n // then, recalculate UTC and local from \"old\" time with the new offset\n if (value?.utc) {\n const desiredDateTime = unlocalizeDateTime(value.utc, value.timezone)\n const newUtcDateObject = zonedTimeToUtc(desiredDateTime, newTimezone.name)\n const newOffset = getTimezoneOffset(newTimezone.name, newUtcDateObject) / 60 / 1000\n const newLocalDate = formatInTimeZone(\n newUtcDateObject.toISOString(),\n newTimezone.name,\n \"yyyy-MM-dd'T'HH:mm:ssXXX\",\n )\n patches.push(set(newUtcDateObject.toISOString(), ['utc']))\n patches.push(set(newLocalDate, ['local']))\n patches.push(set(newOffset, ['offset']))\n }\n onChange(patches)\n },\n [onChange, userTz, value],\n )\n\n return (\n // taken from Scheduled Publishing, again!\n // https://github.com/sanity-io/sanity-plugin-scheduled-publishing/blob/bb282e3df9a8a73df37fab8ee1fdd0e2430745be/src/components/dialogs/DialogTimeZone.tsx#L100\n <Box padding={4}>\n <Autocomplete\n fontSize={2}\n icon={SearchIcon}\n id=\"timezone\"\n onChange={handleTimezoneChange}\n openButton\n options={allTimezones}\n padding={4}\n placeholder=\"Search for a city or time zone\"\n popover={{\n boundaryElement: document.querySelector('body'),\n constrainSize: true,\n placement: 'bottom-start',\n }}\n // eslint-disable-next-line react/jsx-no-bind\n renderOption={(option) => {\n return (\n <Card as=\"button\" padding={3}>\n <Text size={1} textOverflow=\"ellipsis\">\n <span>GMT{option.offset}</span>\n <span style={{fontWeight: 500, marginLeft: '1em'}}>{option.alternativeName}</span>\n <span style={{marginLeft: '1em'}}>{option.mainCities}</span>\n </Text>\n </Card>\n )\n }}\n // eslint-disable-next-line react/jsx-no-bind\n renderValue={(_, option) => {\n if (!option) return ''\n return `${option.alternativeName} (${option.namePretty})`\n }}\n tabIndex={-1}\n value={currentTz?.value ?? userTz.value}\n />\n </Box>\n )\n}\n","import {Box, Dialog, Flex} from '@sanity/ui'\nimport {type ReactNode, useCallback, useState} from 'react'\nimport {ObjectInputMember, ObjectInputProps} from 'sanity'\n\nimport {RichDate} from '../types'\nimport {RelativeDateTimePicker} from './RelativeDateTimePicker'\nimport {TimezoneButton} from './TimezoneButton'\nimport {TimezoneSelector} from './TimezoneSelector'\n\nexport const RichDateInput = (props: ObjectInputProps): ReactNode => {\n const {onChange, value, members, schemaType} = props\n const {options} = schemaType\n const localMember = members.find((member) => member.kind === 'field' && member.name === 'local')\n const timezoneMember = members.find(\n (member) => member.kind === 'field' && member.name === 'timezone',\n )\n const [timezoneSelectorOpen, setTimezoneSelectorOpen] = useState(false)\n const onClose = useCallback(() => setTimezoneSelectorOpen(false), [])\n const onOpen = useCallback(() => setTimezoneSelectorOpen(true), [])\n\n return (\n <>\n <Flex>\n <Box flex={[1, 2, 4]}>\n {localMember && (\n <ObjectInputMember\n {...props}\n member={localMember}\n // eslint-disable-next-line react/jsx-no-bind\n renderInput={(renderInputProps) => (\n <RelativeDateTimePicker\n {...renderInputProps}\n dateValue={value as RichDate}\n schemaType={{...renderInputProps.schemaType, options}}\n onChange={onChange}\n />\n )}\n />\n )}\n </Box>\n <Box flex={[1]} marginLeft={[2, 2, 3, 4]}>\n {timezoneMember && (\n <ObjectInputMember\n {...props}\n member={timezoneMember}\n // eslint-disable-next-line react/jsx-no-bind\n renderInput={() => (\n <TimezoneButton onClick={onOpen} timezone={value?.timezone ?? ''} />\n )}\n />\n )}\n </Box>\n </Flex>\n {timezoneSelectorOpen && (\n <Dialog onClose={onClose} header=\"Select a timezone\" id=\"timezone-select\" width={1}>\n <TimezoneSelector onChange={onChange} value={value as RichDate} />\n </Dialog>\n )}\n </>\n )\n}\n","import {\n DatetimeDefinition,\n defineField,\n defineType,\n ObjectDefinition,\n ObjectSchemaType,\n} from 'sanity'\n\nimport {RichDateInput} from './components/RichDateInput'\n\nconst richDateTypeName = 'richDate' as const\n\nexport type RichDateSchemaType = Omit<ObjectSchemaType, 'options'> & {\n options?: DatetimeDefinition['options']\n}\n\n/**\n * @public\n */\nexport interface RichDateDefinition extends Omit<ObjectDefinition, 'type' | 'fields' | 'options'> {\n type: typeof richDateTypeName\n options?: DatetimeDefinition['options']\n}\n\ndeclare module 'sanity' {\n //allows the custom input to be valid for the schema def\n export interface IntrinsicDefinitions {\n richDate: RichDateDefinition\n }\n}\n\nexport const richDateSchema = defineType({\n name: richDateTypeName,\n title: 'Rich Date',\n type: 'object',\n fields: [\n defineField({\n name: 'local',\n title: 'Local',\n type: 'string',\n }),\n defineField({\n name: 'utc',\n title: 'UTC',\n type: 'string',\n }),\n defineField({\n name: 'timezone',\n title: 'Timezone',\n type: 'string',\n }),\n defineField({\n name: 'offset',\n title: 'Offset',\n type: 'number',\n }),\n ],\n\n components: {\n input: RichDateInput,\n },\n})\n","import {definePlugin} from 'sanity'\n\nimport {RichDateDefinition, richDateSchema, RichDateSchemaType} from './schema'\nimport {RichDate} from './types'\n\nexport const richDate = definePlugin({\n name: 'v3-rich-date-input',\n schema: {\n types: [richDateSchema],\n },\n})\n\nexport type {RichDate, RichDateDefinition, RichDateSchemaType}\n"],"names":["unlocalizeDateTime","datetime","timezone","formatInTimeZone","getConstructedUTCDate","utc","offset","date","Date","currentOffset","getTimezoneOffset","diff","fakeUTCDate","getTime","toISOString","allTimezones","getTimeZones","map","tz","abbreviation","alternativeName","mainCities","join","name","namePretty","replaceAll","currentTimeFormat","split","value","concat","currentTimeOffsetInMinutes","group","RelativeDateTimePicker","props","dateValue","onChange","handleDateChange","useCallback","patch","_a","Intl","DateTimeFormat","resolvedOptions","timeZone","newDatetime","type","unset","desiredDateTime","newUtcDateObject","zonedTimeToUtc","newOffset","localDate","patches","push","set","dateToDisplay","DateTimeInput","TimezoneButton","_b","_c","_d","_e","onClick","currentTimezone","label","find","includes","jsx","Button","fontSize","style","width","justify","icon","EarthAmericasIcon","mode","text","TimezoneSelector","currentTz","userTzName","userTz","handleTimezoneChange","selectedTz","newTimezone","timezonePatch","newLocalDate","Box","padding","children","Autocomplete","SearchIcon","id","openButton","options","placeholder","popover","boundaryElement","document","querySelector","constrainSize","placement","renderOption","option","Card","as","jsxs","Text","size","textOverflow","fontWeight","marginLeft","renderValue","_","tabIndex","RichDateInput","members","schemaType","localMember","member","kind","timezoneMember","timezoneSelectorOpen","setTimezoneSelectorOpen","useState","onClose","onOpen","Fragment","Flex","flex","ObjectInputMember","renderInput","renderInputProps","Dialog","header","richDateTypeName","richDateSchema","defineType","title","fields","defineField","components","input","richDate","definePlugin","schema","types"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/rich-date-input",
3
- "version": "3.0.3",
3
+ "version": "3.0.5",
4
4
  "description": "A timezone-aware datetime type and input component for Sanity Studio",
5
5
  "keywords": [
6
6
  "sanity",
@@ -53,10 +53,10 @@
53
53
  "prepare": "husky install"
54
54
  },
55
55
  "dependencies": {
56
- "@sanity/icons": "^2.11.8",
57
- "@sanity/incompatible-plugin": "^1.0.4",
58
- "@sanity/ui": "^2.5.0",
59
- "@vvo/tzdb": "^6.140.0",
56
+ "@sanity/icons": "^3.5.3",
57
+ "@sanity/incompatible-plugin": "^1.0.5",
58
+ "@sanity/ui": "^2.10.11",
59
+ "@vvo/tzdb": "^6.154.0",
60
60
  "date-fns": "^2.30.0",
61
61
  "date-fns-tz": "^2.0.1"
62
62
  },
@@ -89,7 +89,7 @@
89
89
  "typescript": "^5.5.2"
90
90
  },
91
91
  "peerDependencies": {
92
- "react": "^18",
92
+ "react": "^18 || ^19",
93
93
  "sanity": "^3"
94
94
  },
95
95
  "engines": {
@@ -1,56 +1,59 @@
1
- import {DateTimeInput, FormPatch, PatchEvent, InputProps, set, unset} from 'sanity'
1
+ import {formatInTimeZone, getTimezoneOffset, zonedTimeToUtc} from 'date-fns-tz'
2
+ import {type ReactNode, useCallback} from 'react'
3
+ import {DateTimeInput, FormPatch, InputProps, PatchEvent, set, unset} from 'sanity'
2
4
 
3
- import {getConstructedUTCDate, unlocalizeDateTime} from '../utils'
4
5
  import {RichDate} from '../types'
5
- import {formatInTimeZone, zonedTimeToUtc} from 'date-fns-tz'
6
+ import {getConstructedUTCDate, unlocalizeDateTime} from '../utils'
6
7
 
7
8
  interface RelativeDateTimePickerProps extends Omit<InputProps, 'renderDefault'> {
8
9
  dateValue?: RichDate
9
10
  }
10
-
11
- export const RelativeDateTimePicker = (props: RelativeDateTimePickerProps) => {
12
- const value = props.dateValue
13
- const timezone = value?.timezone ?? Intl.DateTimeFormat().resolvedOptions().timeZone
14
- /*
15
- * if our offset is not coming from a lib, we have to reverse it
16
- * to get the real offset used everywhere
17
- * https://momentjscom.readthedocs.io/en/latest/moment/03-manipulating/09-utc-offset/
18
- */
19
- const offset = value?.offset ?? new Date().getTimezoneOffset() * -1
20
- const handleDateChange = (patch: FormPatch | PatchEvent | FormPatch[]) => {
21
- const patches = []
22
- const newDatetime = (patch as unknown as {value: string})?.value
23
- if (!newDatetime || !('type' in patch) || patch.type !== 'set') {
24
- props.onChange(unset())
25
- return
26
- }
27
-
28
- //get what time the user "meant" to set without tz info
29
- //since the datepicker always localizes to the user's timezone
30
- const desiredDateTime = unlocalizeDateTime(
31
- newDatetime,
32
- Intl.DateTimeFormat().resolvedOptions().timeZone,
33
- )
34
-
35
- //use the user-selected timezone here
36
- const utcDate = zonedTimeToUtc(desiredDateTime, timezone).toISOString()
37
- const localDate = formatInTimeZone(utcDate, timezone, "yyyy-MM-dd'T'HH:mm:ssXXX")
38
-
39
- patches.push(set(utcDate, ['utc']))
40
- patches.push(set(localDate, ['local']))
41
-
42
- if (!value?.timezone) {
43
- patches.push(set(timezone, ['timezone']))
44
- }
45
-
46
- if (!value?.offset) {
47
- patches.push(set(offset, ['offset']))
48
- }
49
-
50
- props.onChange(patches)
51
- }
11
+ export const RelativeDateTimePicker = (props: RelativeDateTimePickerProps): ReactNode => {
12
+ const {dateValue: value, onChange} = props
13
+
14
+ const handleDateChange = useCallback(
15
+ (patch: FormPatch | PatchEvent | FormPatch[]) => {
16
+ const timezone = value?.timezone ?? Intl.DateTimeFormat().resolvedOptions().timeZone
17
+ const newDatetime = (patch as unknown as {value: string})?.value
18
+ if (!newDatetime || !('type' in patch) || patch.type !== 'set') {
19
+ onChange(unset())
20
+ return
21
+ }
22
+
23
+ /* get what time the user "meant" to set without tz info
24
+ * right now, newDatetime is the time the user set plus
25
+ * their current offset, not the timezone offset
26
+ */
27
+ const desiredDateTime = unlocalizeDateTime(
28
+ newDatetime,
29
+ Intl.DateTimeFormat().resolvedOptions().timeZone,
30
+ )
31
+
32
+ const newUtcDateObject = zonedTimeToUtc(desiredDateTime, timezone)
33
+ // offset may have changed based on DST, capture that
34
+ const newOffset = getTimezoneOffset(timezone, newUtcDateObject) / 60 / 1000
35
+ const localDate = formatInTimeZone(newUtcDateObject, timezone, "yyyy-MM-dd'T'HH:mm:ssXXX")
36
+
37
+ const patches = []
38
+
39
+ patches.push(set(newUtcDateObject.toISOString(), ['utc']))
40
+ patches.push(set(localDate, ['local']))
41
+
42
+ if (!value?.timezone) {
43
+ patches.push(set(timezone, ['timezone']))
44
+ }
45
+
46
+ if (value?.offset !== newOffset) {
47
+ patches.push(set(newOffset, ['offset']))
48
+ }
49
+
50
+ onChange(patches)
51
+ },
52
+ [onChange, value],
53
+ )
52
54
 
53
55
  const dateToDisplay = value?.utc ? getConstructedUTCDate(value.utc, value.offset) : ''
54
- //@ts-expect-error -- slight mismatch in elementProps and renderDefault, but should line up in practice
56
+
57
+ // @ts-expect-error -- slight mismatch in elementProps and renderDefault, but should line up in practice
55
58
  return <DateTimeInput {...props} onChange={handleDateChange} value={dateToDisplay} />
56
59
  }
@@ -1,12 +1,13 @@
1
+ import {Box, Dialog, Flex} from '@sanity/ui'
2
+ import {type ReactNode, useCallback, useState} from 'react'
1
3
  import {ObjectInputMember, ObjectInputProps} from 'sanity'
2
- import {Box, Flex, Dialog} from '@sanity/ui'
4
+
5
+ import {RichDate} from '../types'
3
6
  import {RelativeDateTimePicker} from './RelativeDateTimePicker'
4
- import {TimezoneSelector} from './TimezoneSelector'
5
- import {useCallback, useState} from 'react'
6
7
  import {TimezoneButton} from './TimezoneButton'
7
- import {RichDate} from '../types'
8
+ import {TimezoneSelector} from './TimezoneSelector'
8
9
 
9
- export const RichDateInput = (props: ObjectInputProps) => {
10
+ export const RichDateInput = (props: ObjectInputProps): ReactNode => {
10
11
  const {onChange, value, members, schemaType} = props
11
12
  const {options} = schemaType
12
13
  const localMember = members.find((member) => member.kind === 'field' && member.name === 'local')
@@ -25,6 +26,7 @@ export const RichDateInput = (props: ObjectInputProps) => {
25
26
  <ObjectInputMember
26
27
  {...props}
27
28
  member={localMember}
29
+ // eslint-disable-next-line react/jsx-no-bind
28
30
  renderInput={(renderInputProps) => (
29
31
  <RelativeDateTimePicker
30
32
  {...renderInputProps}
@@ -41,6 +43,7 @@ export const RichDateInput = (props: ObjectInputProps) => {
41
43
  <ObjectInputMember
42
44
  {...props}
43
45
  member={timezoneMember}
46
+ // eslint-disable-next-line react/jsx-no-bind
44
47
  renderInput={() => (
45
48
  <TimezoneButton onClick={onOpen} timezone={value?.timezone ?? ''} />
46
49
  )}
@@ -1,5 +1,7 @@
1
- import {Button} from '@sanity/ui'
2
1
  import {EarthAmericasIcon} from '@sanity/icons'
2
+ import {Button} from '@sanity/ui'
3
+ import {type ReactNode} from 'react'
4
+
3
5
  import {allTimezones} from '../utils'
4
6
 
5
7
  interface TimezoneButtonProps {
@@ -7,7 +9,7 @@ interface TimezoneButtonProps {
7
9
  timezone: string
8
10
  }
9
11
 
10
- export const TimezoneButton = (props: TimezoneButtonProps) => {
12
+ export const TimezoneButton = (props: TimezoneButtonProps): ReactNode => {
11
13
  const {onClick, timezone} = props
12
14
  const currentTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone
13
15
 
@@ -1,49 +1,54 @@
1
1
  import {SearchIcon} from '@sanity/icons'
2
+ import {Autocomplete, Box, Card, Text} from '@sanity/ui'
3
+ import {formatInTimeZone, getTimezoneOffset, zonedTimeToUtc} from 'date-fns-tz'
4
+ import {type ReactNode, useCallback} from 'react'
2
5
  import {ObjectInputProps, set} from 'sanity'
3
- import {allTimezones, unlocalizeDateTime} from '../utils'
6
+
4
7
  import {NormalizedTimeZone, RichDate} from '../types'
5
- import {Autocomplete, Card, Text, Box} from '@sanity/ui'
6
- import {formatInTimeZone, zonedTimeToUtc} from 'date-fns-tz'
8
+ import {allTimezones, unlocalizeDateTime} from '../utils'
7
9
 
8
10
  interface TimezoneSelectorProps {
9
11
  onChange: Pick<ObjectInputProps, 'onChange'>['onChange']
10
12
  value?: RichDate
11
13
  }
12
14
 
13
- export const TimezoneSelector = (props: TimezoneSelectorProps) => {
15
+ export const TimezoneSelector = (props: TimezoneSelectorProps): ReactNode => {
14
16
  const {onChange, value} = props
15
17
  const currentTz = allTimezones.find((tz) => tz.name === value?.timezone)
16
18
  const userTzName = Intl.DateTimeFormat().resolvedOptions().timeZone
17
19
  const userTz = (allTimezones.find((tz) => tz.name === userTzName) ??
18
20
  allTimezones.find((tz) => tz.group.includes(userTzName)))!
19
21
 
20
- const handleTimezoneChange = (selectedTz: string) => {
21
- const newTimezone =
22
- allTimezones.find((tz) => tz.value === selectedTz) ?? (userTz as NormalizedTimeZone)
22
+ const handleTimezoneChange = useCallback(
23
+ (selectedTz: string) => {
24
+ const newTimezone =
25
+ allTimezones.find((tz) => tz.value === selectedTz) ?? (userTz as NormalizedTimeZone)
23
26
 
24
- const offset = newTimezone.currentTimeOffsetInMinutes ?? 0
25
- const timezonePatch = set(newTimezone.name, ['timezone'])
26
- const offsetPatch = set(offset, ['offset'])
27
- const patches = [timezonePatch, offsetPatch]
27
+ const timezonePatch = set(newTimezone.name, ['timezone'])
28
+ const patches = [timezonePatch]
28
29
 
29
- //then, recalculate UTC and local from "old" time with the new offset
30
- if (value?.utc) {
31
- const desiredDateTime = unlocalizeDateTime(value.utc, value.timezone)
32
- const newUtcDate = zonedTimeToUtc(desiredDateTime, newTimezone.name).toISOString()
33
- const newLocalDate = formatInTimeZone(
34
- newUtcDate,
35
- newTimezone.name,
36
- "yyyy-MM-dd'T'HH:mm:ssXXX",
37
- )
38
- patches.push(set(newUtcDate, ['utc']))
39
- patches.push(set(newLocalDate, ['local']))
40
- }
41
- onChange(patches)
42
- }
30
+ // then, recalculate UTC and local from "old" time with the new offset
31
+ if (value?.utc) {
32
+ const desiredDateTime = unlocalizeDateTime(value.utc, value.timezone)
33
+ const newUtcDateObject = zonedTimeToUtc(desiredDateTime, newTimezone.name)
34
+ const newOffset = getTimezoneOffset(newTimezone.name, newUtcDateObject) / 60 / 1000
35
+ const newLocalDate = formatInTimeZone(
36
+ newUtcDateObject.toISOString(),
37
+ newTimezone.name,
38
+ "yyyy-MM-dd'T'HH:mm:ssXXX",
39
+ )
40
+ patches.push(set(newUtcDateObject.toISOString(), ['utc']))
41
+ patches.push(set(newLocalDate, ['local']))
42
+ patches.push(set(newOffset, ['offset']))
43
+ }
44
+ onChange(patches)
45
+ },
46
+ [onChange, userTz, value],
47
+ )
43
48
 
44
49
  return (
45
- //taken from Scheduled Publishing, again!
46
- //https://github.com/sanity-io/sanity-plugin-scheduled-publishing/blob/bb282e3df9a8a73df37fab8ee1fdd0e2430745be/src/components/dialogs/DialogTimeZone.tsx#L100
50
+ // taken from Scheduled Publishing, again!
51
+ // https://github.com/sanity-io/sanity-plugin-scheduled-publishing/blob/bb282e3df9a8a73df37fab8ee1fdd0e2430745be/src/components/dialogs/DialogTimeZone.tsx#L100
47
52
  <Box padding={4}>
48
53
  <Autocomplete
49
54
  fontSize={2}
@@ -59,6 +64,7 @@ export const TimezoneSelector = (props: TimezoneSelectorProps) => {
59
64
  constrainSize: true,
60
65
  placement: 'bottom-start',
61
66
  }}
67
+ // eslint-disable-next-line react/jsx-no-bind
62
68
  renderOption={(option) => {
63
69
  return (
64
70
  <Card as="button" padding={3}>
@@ -70,6 +76,7 @@ export const TimezoneSelector = (props: TimezoneSelectorProps) => {
70
76
  </Card>
71
77
  )
72
78
  }}
79
+ // eslint-disable-next-line react/jsx-no-bind
73
80
  renderValue={(_, option) => {
74
81
  if (!option) return ''
75
82
  return `${option.alternativeName} (${option.namePretty})`
package/src/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import {definePlugin} from 'sanity'
2
- import {richDateSchema, RichDateDefinition, RichDateSchemaType} from './schema'
2
+
3
+ import {RichDateDefinition, richDateSchema, RichDateSchemaType} from './schema'
3
4
  import {RichDate} from './types'
4
5
 
5
6
  export const richDate = definePlugin({
@@ -9,4 +10,4 @@ export const richDate = definePlugin({
9
10
  },
10
11
  })
11
12
 
12
- export type {RichDateDefinition, RichDateSchemaType, RichDate}
13
+ export type {RichDate, RichDateDefinition, RichDateSchemaType}
package/src/schema.ts CHANGED
@@ -1,10 +1,11 @@
1
1
  import {
2
2
  DatetimeDefinition,
3
- ObjectDefinition,
4
- ObjectSchemaType,
5
3
  defineField,
6
4
  defineType,
5
+ ObjectDefinition,
6
+ ObjectSchemaType,
7
7
  } from 'sanity'
8
+
8
9
  import {RichDateInput} from './components/RichDateInput'
9
10
 
10
11
  const richDateTypeName = 'richDate' as const
@@ -1,7 +1,8 @@
1
1
  import {getTimeZones} from '@vvo/tzdb'
2
- import {NormalizedTimeZone} from '../types'
3
2
  import {formatInTimeZone} from 'date-fns-tz'
4
3
 
4
+ import {NormalizedTimeZone} from '../types'
5
+
5
6
  export const unlocalizeDateTime = (datetime: string, timezone: string): string => {
6
7
  return formatInTimeZone(datetime, timezone, 'yyyy-MM-dd HH:mm:ss')
7
8
  }
@@ -14,7 +15,7 @@ export const unlocalizeDateTime = (datetime: string, timezone: string): string =
14
15
  */
15
16
  export const getConstructedUTCDate = (utc: string, offset: number): string => {
16
17
  const date = new Date(utc)
17
- const currentOffset = new Date().getTimezoneOffset() * -1
18
+ const currentOffset = date.getTimezoneOffset() * -1
18
19
  const diff = currentOffset - offset
19
20
  const fakeUTCDate = new Date(date.getTime() - diff * 60 * 1000)
20
21
  return fakeUTCDate.toISOString()