react-timezone-select 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -23,7 +23,7 @@ We also have some **more examples** available on Codesandbox using this componen
23
23
  ## 🏗️ Installing
24
24
 
25
25
  ```bash
26
- npm install react-timezone-select
26
+ npm install react-select react-timezone-select
27
27
  ```
28
28
 
29
29
  ## 🔭 Usage
@@ -138,6 +138,32 @@ timezones={{
138
138
  - `maxAbbrLength` - `number` - Truncate `abbrev` labelStyles string to length
139
139
  - Any other [`react-select`](https://github.com/jedwatson/react-select#props) props
140
140
 
141
+ ## 🎨 Custom Select component
142
+
143
+ By default, `react-timezone-select` uses [`react-select`](https://github.com/jedwatson/react-select) as underlying select component. If you'd like to bring your own select component, you can use the `useTimezoneSelect` hook instead of the `TimezoneSelect` component to render the timezones using your self-provided select component.
144
+
145
+ ```jsx
146
+ import { useTimezoneSelect, allTimezones } from 'react-timezone-select'
147
+
148
+ const labelStyle = 'original'
149
+ const timezones = {
150
+ ...allTimezones,
151
+ 'Europe/Berlin': 'Frankfurt'
152
+ }
153
+
154
+ const customSelect = () => {
155
+ const { options, parseTimezone } = useTimezoneSelect({ labelStyle, timezones })
156
+
157
+ return (
158
+ <select onChange={e => onChange(parseTimezone(e.currentTarget.value))}>
159
+ {options.map(option => (
160
+ <option value={option.value}>{option.label}</option>
161
+ ))}
162
+ </select>
163
+ )
164
+ }
165
+ ```
166
+
141
167
  ## 🚧 Contributing
142
168
 
143
169
  Pull requests are always welcome! Please stick to repo settings (prettier, eslint, etc.), and if adding new features, please consider adding test(s) and documentation where appropriate!
package/dist/index.cjs CHANGED
@@ -30,7 +30,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  var src_exports = {};
31
31
  __export(src_exports, {
32
32
  allTimezones: () => timezone_list_default,
33
- default: () => TimezoneSelect
33
+ default: () => TimezoneSelect,
34
+ useTimezoneSelect: () => useTimezoneSelect
34
35
  });
35
36
  module.exports = __toCommonJS(src_exports);
36
37
  var React = __toESM(require("react"), 1);
@@ -123,24 +124,24 @@ var allTimezones = {
123
124
  var timezone_list_default = allTimezones;
124
125
 
125
126
  // src/index.tsx
126
- var TimezoneSelect = ({
127
- value,
128
- onBlur,
129
- onChange,
130
- labelStyle = "original",
127
+ function useTimezoneSelect({
131
128
  timezones = timezone_list_default,
132
- maxAbbrLength = 4,
133
- ...props
134
- }) => {
135
- const getOptions = React.useMemo(
136
- () => Object.entries(timezones).reduce((selectOptions, zone) => {
129
+ labelStyle = "original",
130
+ maxAbbrLength = 4
131
+ }) {
132
+ const options = React.useMemo(() => {
133
+ return Object.entries(timezones).map((zone) => {
137
134
  try {
138
135
  const now = import_spacetime.default.now(zone[0]);
139
136
  const tz = now.timezone();
140
137
  const tzStrings = (0, import_timezone_soft.default)(zone[0]);
141
138
  let label = "";
142
- let abbr = now.isDST() ? tzStrings[0].daylight.abbr : tzStrings[0].standard.abbr;
143
- let altName = now.isDST() ? tzStrings[0].daylight.name : tzStrings[0].standard.name;
139
+ const standardAbbr = tzStrings?.[0]?.standard?.abbr ?? "";
140
+ const dstAbbr = tzStrings?.[0]?.daylight?.abbr ?? standardAbbr;
141
+ let abbr = now.isDST() ? dstAbbr : standardAbbr;
142
+ const standardAltName = tzStrings?.[0]?.standard?.name ?? "";
143
+ const dstAltName = tzStrings?.[0]?.daylight?.name ?? standardAltName;
144
+ let altName = now.isDST() ? dstAltName : standardAltName;
144
145
  const min = tz.current.offset * 60;
145
146
  const hr = `${min / 60 ^ 0}:` + (min % 60 === 0 ? "00" : Math.abs(min % 60));
146
147
  const prefix = `(GMT${hr.includes("-") ? hr : `+${hr}`}) ${zone[1]}`;
@@ -149,7 +150,7 @@ var TimezoneSelect = ({
149
150
  label = prefix;
150
151
  break;
151
152
  case "altName":
152
- label = `${prefix} ${altName?.length ? `(${altName})` : ""}`;
153
+ label = `${prefix} ${altName ? `(${altName})` : ""}`;
153
154
  break;
154
155
  case "abbrev":
155
156
  label = `${prefix} (${abbr.substring(0, maxAbbrLength)})`;
@@ -157,23 +158,18 @@ var TimezoneSelect = ({
157
158
  default:
158
159
  label = `${prefix}`;
159
160
  }
160
- selectOptions.push({
161
+ return {
161
162
  value: tz.name,
162
163
  label,
163
164
  offset: tz.current.offset,
164
165
  abbrev: abbr,
165
166
  altName
166
- });
167
- return selectOptions;
167
+ };
168
168
  } catch {
169
- return selectOptions;
169
+ return null;
170
170
  }
171
- }, []).sort((a, b) => a.offset - b.offset),
172
- [labelStyle, timezones]
173
- );
174
- const handleChange = (tz) => {
175
- onChange && onChange(tz);
176
- };
171
+ }).filter(Boolean).sort((a, b) => a.offset - b.offset);
172
+ }, [labelStyle, timezones]);
177
173
  const findFuzzyTz = (zone) => {
178
174
  let currentTime = import_spacetime.default.now("GMT");
179
175
  try {
@@ -181,7 +177,7 @@ var TimezoneSelect = ({
181
177
  } catch (err) {
182
178
  return;
183
179
  }
184
- return getOptions.filter(
180
+ return options.filter(
185
181
  (tz) => tz.offset === currentTime.timezone().current.offset
186
182
  ).map((tz) => {
187
183
  let score = 0;
@@ -210,17 +206,36 @@ var TimezoneSelect = ({
210
206
  if (typeof zone === "object" && zone.value && zone.label)
211
207
  return zone;
212
208
  if (typeof zone === "string") {
213
- return getOptions.find((tz) => tz.value === zone) || zone.indexOf("/") !== -1 && findFuzzyTz(zone);
209
+ return options.find((tz) => tz.value === zone) || zone.indexOf("/") !== -1 && findFuzzyTz(zone);
214
210
  } else if (zone.value && !zone.label) {
215
- return getOptions.find((tz) => tz.value === zone.value);
211
+ return options.find((tz) => tz.value === zone.value);
216
212
  }
217
213
  };
214
+ return { options, parseTimezone };
215
+ }
216
+ var TimezoneSelect = ({
217
+ value,
218
+ onBlur,
219
+ onChange,
220
+ labelStyle,
221
+ maxAbbrLength,
222
+ timezones,
223
+ ...props
224
+ }) => {
225
+ const { options, parseTimezone } = useTimezoneSelect({
226
+ timezones,
227
+ labelStyle,
228
+ maxAbbrLength
229
+ });
230
+ const handleChange = (tz) => {
231
+ onChange && onChange(tz);
232
+ };
218
233
  return /* @__PURE__ */ React.createElement(
219
234
  import_react_select.default,
220
235
  {
221
236
  value: parseTimezone(value),
222
237
  onChange: handleChange,
223
- options: getOptions,
238
+ options,
224
239
  onBlur,
225
240
  ...props
226
241
  }
@@ -228,5 +243,6 @@ var TimezoneSelect = ({
228
243
  };
229
244
  // Annotate the CommonJS export names for ESM import in node:
230
245
  0 && (module.exports = {
231
- allTimezones
246
+ allTimezones,
247
+ useTimezoneSelect
232
248
  });
package/dist/index.d.ts CHANGED
@@ -4,24 +4,30 @@ declare type ICustomTimezone = {
4
4
  [key: string]: string;
5
5
  };
6
6
  declare type ILabelStyle = 'original' | 'altName' | 'abbrev';
7
- interface ITimezoneOption {
7
+ declare type ITimezoneOption = {
8
8
  value: string;
9
9
  label: string;
10
10
  abbrev?: string;
11
11
  altName?: string;
12
12
  offset?: number;
13
- }
13
+ };
14
14
  declare type ITimezone = ITimezoneOption | string;
15
- interface Props extends Omit<Props$1<ITimezone, false>, 'onChange'> {
16
- value: ITimezone;
15
+ declare type TimezoneSelectOptions = {
17
16
  labelStyle?: ILabelStyle;
18
- onChange?: (timezone: ITimezoneOption) => void;
19
17
  timezones?: ICustomTimezone;
20
18
  maxAbbrLength?: number;
21
- }
19
+ };
20
+ declare type Props = Omit<Props$1<ITimezone, false>, 'onChange'> & TimezoneSelectOptions & {
21
+ value: ITimezone;
22
+ onChange?: (timezone: ITimezoneOption) => void;
23
+ };
22
24
 
23
25
  declare const allTimezones: ICustomTimezone;
24
26
 
25
- declare const TimezoneSelect: ({ value, onBlur, onChange, labelStyle, timezones, maxAbbrLength, ...props }: Props) => JSX.Element;
27
+ declare function useTimezoneSelect({ timezones, labelStyle, maxAbbrLength, }: TimezoneSelectOptions): {
28
+ parseTimezone: (zone: ITimezone) => ITimezoneOption;
29
+ options: ITimezoneOption[];
30
+ };
31
+ declare const TimezoneSelect: ({ value, onBlur, onChange, labelStyle, maxAbbrLength, timezones, ...props }: Props) => JSX.Element;
26
32
 
27
- export { ILabelStyle, ITimezone, ITimezoneOption, Props, allTimezones, TimezoneSelect as default };
33
+ export { ILabelStyle, ITimezone, ITimezoneOption, Props, TimezoneSelectOptions, allTimezones, TimezoneSelect as default, useTimezoneSelect };
package/dist/index.js CHANGED
@@ -89,24 +89,24 @@ var allTimezones = {
89
89
  var timezone_list_default = allTimezones;
90
90
 
91
91
  // src/index.tsx
92
- var TimezoneSelect = ({
93
- value,
94
- onBlur,
95
- onChange,
96
- labelStyle = "original",
92
+ function useTimezoneSelect({
97
93
  timezones = timezone_list_default,
98
- maxAbbrLength = 4,
99
- ...props
100
- }) => {
101
- const getOptions = React.useMemo(
102
- () => Object.entries(timezones).reduce((selectOptions, zone) => {
94
+ labelStyle = "original",
95
+ maxAbbrLength = 4
96
+ }) {
97
+ const options = React.useMemo(() => {
98
+ return Object.entries(timezones).map((zone) => {
103
99
  try {
104
100
  const now = spacetime.now(zone[0]);
105
101
  const tz = now.timezone();
106
102
  const tzStrings = soft(zone[0]);
107
103
  let label = "";
108
- let abbr = now.isDST() ? tzStrings[0].daylight.abbr : tzStrings[0].standard.abbr;
109
- let altName = now.isDST() ? tzStrings[0].daylight.name : tzStrings[0].standard.name;
104
+ const standardAbbr = tzStrings?.[0]?.standard?.abbr ?? "";
105
+ const dstAbbr = tzStrings?.[0]?.daylight?.abbr ?? standardAbbr;
106
+ let abbr = now.isDST() ? dstAbbr : standardAbbr;
107
+ const standardAltName = tzStrings?.[0]?.standard?.name ?? "";
108
+ const dstAltName = tzStrings?.[0]?.daylight?.name ?? standardAltName;
109
+ let altName = now.isDST() ? dstAltName : standardAltName;
110
110
  const min = tz.current.offset * 60;
111
111
  const hr = `${min / 60 ^ 0}:` + (min % 60 === 0 ? "00" : Math.abs(min % 60));
112
112
  const prefix = `(GMT${hr.includes("-") ? hr : `+${hr}`}) ${zone[1]}`;
@@ -115,7 +115,7 @@ var TimezoneSelect = ({
115
115
  label = prefix;
116
116
  break;
117
117
  case "altName":
118
- label = `${prefix} ${altName?.length ? `(${altName})` : ""}`;
118
+ label = `${prefix} ${altName ? `(${altName})` : ""}`;
119
119
  break;
120
120
  case "abbrev":
121
121
  label = `${prefix} (${abbr.substring(0, maxAbbrLength)})`;
@@ -123,23 +123,18 @@ var TimezoneSelect = ({
123
123
  default:
124
124
  label = `${prefix}`;
125
125
  }
126
- selectOptions.push({
126
+ return {
127
127
  value: tz.name,
128
128
  label,
129
129
  offset: tz.current.offset,
130
130
  abbrev: abbr,
131
131
  altName
132
- });
133
- return selectOptions;
132
+ };
134
133
  } catch {
135
- return selectOptions;
134
+ return null;
136
135
  }
137
- }, []).sort((a, b) => a.offset - b.offset),
138
- [labelStyle, timezones]
139
- );
140
- const handleChange = (tz) => {
141
- onChange && onChange(tz);
142
- };
136
+ }).filter(Boolean).sort((a, b) => a.offset - b.offset);
137
+ }, [labelStyle, timezones]);
143
138
  const findFuzzyTz = (zone) => {
144
139
  let currentTime = spacetime.now("GMT");
145
140
  try {
@@ -147,7 +142,7 @@ var TimezoneSelect = ({
147
142
  } catch (err) {
148
143
  return;
149
144
  }
150
- return getOptions.filter(
145
+ return options.filter(
151
146
  (tz) => tz.offset === currentTime.timezone().current.offset
152
147
  ).map((tz) => {
153
148
  let score = 0;
@@ -176,17 +171,36 @@ var TimezoneSelect = ({
176
171
  if (typeof zone === "object" && zone.value && zone.label)
177
172
  return zone;
178
173
  if (typeof zone === "string") {
179
- return getOptions.find((tz) => tz.value === zone) || zone.indexOf("/") !== -1 && findFuzzyTz(zone);
174
+ return options.find((tz) => tz.value === zone) || zone.indexOf("/") !== -1 && findFuzzyTz(zone);
180
175
  } else if (zone.value && !zone.label) {
181
- return getOptions.find((tz) => tz.value === zone.value);
176
+ return options.find((tz) => tz.value === zone.value);
182
177
  }
183
178
  };
179
+ return { options, parseTimezone };
180
+ }
181
+ var TimezoneSelect = ({
182
+ value,
183
+ onBlur,
184
+ onChange,
185
+ labelStyle,
186
+ maxAbbrLength,
187
+ timezones,
188
+ ...props
189
+ }) => {
190
+ const { options, parseTimezone } = useTimezoneSelect({
191
+ timezones,
192
+ labelStyle,
193
+ maxAbbrLength
194
+ });
195
+ const handleChange = (tz) => {
196
+ onChange && onChange(tz);
197
+ };
184
198
  return /* @__PURE__ */ React.createElement(
185
199
  Select,
186
200
  {
187
201
  value: parseTimezone(value),
188
202
  onChange: handleChange,
189
- options: getOptions,
203
+ options,
190
204
  onBlur,
191
205
  ...props
192
206
  }
@@ -194,5 +208,6 @@ var TimezoneSelect = ({
194
208
  };
195
209
  export {
196
210
  timezone_list_default as allTimezones,
197
- TimezoneSelect as default
211
+ TimezoneSelect as default,
212
+ useTimezoneSelect
198
213
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-timezone-select",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "Usable, dynamic React Timezone Select",
5
5
  "scripts": {
6
6
  "dev": "concurrently \"tsup src/index.tsx --format esm --watch\" \"cd example && pnpm dev\"",