nitro-web 0.0.108 → 0.0.109

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.
@@ -1,4 +1,4 @@
1
- import { DayPicker, getDefaultClassNames } from 'react-day-picker'
1
+ import { DayPicker, getDefaultClassNames, DayPickerProps as DayPickerPropsBase } from 'react-day-picker'
2
2
  import { isValid } from 'date-fns'
3
3
  import 'react-day-picker/style.css'
4
4
  import { IsFirstRender } from 'nitro-web'
@@ -11,8 +11,10 @@ type ModeSelection<T extends Mode> = (
11
11
  : T extends 'multiple' ? Date[]
12
12
  : { from?: Date; to?: Date }
13
13
  )
14
+ export type DayPickerProps = Omit<DayPickerPropsBase,
15
+ 'mode' | 'selected' | 'onSelect' | 'modifiersClassNames' | 'classNames' | 'numberOfMonths' | 'month' | 'onMonthChange'>
14
16
 
15
- export type CalendarProps = {
17
+ export type CalendarProps = DayPickerProps & {
16
18
  mode?: Mode
17
19
  onChange?: (mode: Mode, value: null|number|(null|number)[]) => void
18
20
  value?: null|number|string|(null|number|string)[]
@@ -22,7 +24,8 @@ export type CalendarProps = {
22
24
  preserveTime?: boolean // just for single mode
23
25
  }
24
26
 
25
- export function Calendar({ mode='single', onChange, value, numberOfMonths, month: monthProp, className, preserveTime }: CalendarProps) {
27
+ export function Calendar({ mode='single', onChange, value, numberOfMonths, month: monthProp, className, preserveTime,
28
+ ...props }: CalendarProps) {
26
29
  const isFirstRender = IsFirstRender()
27
30
  const isRange = mode == 'range'
28
31
 
@@ -113,11 +116,11 @@ export function Calendar({ mode='single', onChange, value, numberOfMonths, month
113
116
  <div>
114
117
  {
115
118
  mode === 'single' ? (
116
- <DayPicker mode="single" selected={dates[0]} {...common} className={className} />
119
+ <DayPicker {...props} {...common} mode="single" selected={dates[0]} className={className} />
117
120
  ) : mode === 'range' ? (
118
- <DayPicker mode="range" selected={{ from: dates[0], to: dates[1] }} {...common} className={className} />
121
+ <DayPicker {...props} {...common} mode="range" selected={{ from: dates[0], to: dates[1] }} className={className} />
119
122
  ) : (
120
- <DayPicker mode="multiple" selected={dates.filter((d) => !!d)} {...common} className={className} />
123
+ <DayPicker {...props} {...common} mode="multiple" selected={dates.filter((d) => !!d)} className={className} />
121
124
  )
122
125
  }
123
126
  </div>
@@ -18,21 +18,20 @@ type NumericFormatProps = React.InputHTMLAttributes<HTMLInputElement> & {
18
18
  export type FieldCurrencyProps = NumericFormatProps & {
19
19
  name: string
20
20
  /** name is applied if id is not provided */
21
- id?: string
22
- /** e.g. { currencies: { nzd: { symbol: '$', digits: 2 } } } (check out the nitro example for more info) */
23
- config: {
24
- currencies: { [key: string]: { symbol: string, digits: number } },
25
- countries: { [key: string]: { numberFormats: { currency: string } } }
26
- }
21
+ id?: string
27
22
  /** currency iso, e.g. 'nzd' */
28
23
  currency: string
24
+ /** override the default currencies array used to lookup currency symbol and digits, e.g. {nzd: { symbol: '$', digits: 2 }} */
25
+ currencies?: { [key: string]: { symbol: string, digits: number } },
26
+ /** override the default CLDR country currency format, e.g. '¤#,##0.00' */
27
+ format?: string,
29
28
  onChange?: (event: { target: { name: string, value: string|number|null } }) => void
30
29
  /** value should be in cents */
31
30
  value?: string|number|null
32
31
  defaultValue?: number | string | null
33
32
  }
34
33
 
35
- export function FieldCurrency({ config, currency='nzd', onChange, value, defaultValue, ...props }: FieldCurrencyProps) {
34
+ export function FieldCurrency({ currency='nzd', currencies, format, onChange, value, defaultValue, ...props }: FieldCurrencyProps) {
36
35
  const [dontFix, setDontFix] = useState(false)
37
36
  const [settings, setSettings] = useState(() => getCurrencySettings(currency))
38
37
  const [dollars, setDollars] = useState(() => toDollars(value, true, settings))
@@ -61,7 +60,7 @@ export function FieldCurrency({ config, currency='nzd', onChange, value, default
61
60
 
62
61
  useEffect(() => {
63
62
  // Get the prefix content width
64
- setPrefixWidth(settings.prefix == '$' ? getPrefixWidth(settings.prefix, 1) : 0)
63
+ setPrefixWidth(settings.prefix ? getPrefixWidth(settings.prefix, 1) : 0)
65
64
  }, [settings.prefix])
66
65
 
67
66
  function toCents(value?: string|number|null) {
@@ -95,29 +94,33 @@ export function FieldCurrency({ config, currency='nzd', onChange, value, default
95
94
  prefix?: string, // e.g. '$'
96
95
  suffix?: string // e.g. ''
97
96
  } = { currency }
98
- const { symbol, digits } = config.currencies[currency]
99
- let format = config.countries['nz'].numberFormats.currency
97
+
98
+ let _format = format || defaultFormat
99
+ const _currencies = currencies ?? defaultCurrencies
100
+ const currencyObject = _currencies[currency as keyof typeof _currencies]
101
+ const symbol = currencyObject ? currencyObject.symbol : ''
102
+ const digits = currencyObject ? currencyObject.digits : 2
100
103
 
101
104
  // Check for currency symbol (¤) and determine its position
102
- if (format.indexOf('¤') !== -1) {
103
- const position = format.indexOf('¤') === 0 ? 'prefix' : 'suffix'
105
+ if (_format.indexOf('¤') !== -1) {
106
+ const position = _format.indexOf('¤') === 0 ? 'prefix' : 'suffix'
104
107
  output[position] = symbol
105
- format = format.replace('¤', '')
108
+ _format = _format.replace('¤', '')
106
109
  }
107
110
 
108
111
  // Find and set the thousands separator
109
- const thousandMatch = format.match(/[^0-9#]/)
112
+ const thousandMatch = _format.match(/[^0-9#]/)
110
113
  if (thousandMatch) output.thousandSeparator = thousandMatch[0]
111
114
 
112
115
  // Find and set the decimal separator and fraction digits
113
- const decimalMatch = format.match(/0[^0-9]/)
116
+ const decimalMatch = _format.match(/0[^0-9]/)
114
117
  if (decimalMatch) {
115
118
  output.decimalSeparator = decimalMatch[0].slice(1)
116
119
  if (typeof digits !== 'undefined') {
117
120
  output.minDecimals = digits
118
121
  output.maxDecimals = digits
119
122
  } else {
120
- const fractionDigits = format.split(output.decimalSeparator)[1]
123
+ const fractionDigits = _format.split(output.decimalSeparator)[1]
121
124
  if (fractionDigits) {
122
125
  output.minDecimals = fractionDigits.length
123
126
  output.maxDecimals = fractionDigits.length
@@ -156,3 +159,14 @@ export function FieldCurrency({ config, currency='nzd', onChange, value, default
156
159
  </div>
157
160
  )
158
161
  }
162
+
163
+ const defaultCurrencies = {
164
+ nzd: { symbol: '$', digits: 2 },
165
+ aud: { symbol: '$', digits: 2 },
166
+ usd: { symbol: '$', digits: 2 },
167
+ eur: { symbol: '€', digits: 2 },
168
+ gbp: { symbol: '£', digits: 2 },
169
+ btc: { symbol: '₿', digits: 8 },
170
+ }
171
+
172
+ const defaultFormat = '¤#,##0.00'
@@ -2,7 +2,7 @@
2
2
  import { format, isValid, parse } from 'date-fns'
3
3
  import { getPrefixWidth } from 'nitro-web/util'
4
4
  import { Calendar, Dropdown } from 'nitro-web'
5
- import { dayButtonClassName } from '../element/calendar'
5
+ import { dayButtonClassName, DayPickerProps } from '../element/calendar'
6
6
 
7
7
  type Mode = 'single' | 'multiple' | 'range'
8
8
  type DropdownRef = {
@@ -26,6 +26,8 @@ type PreFieldDateProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onCh
26
26
  Icon?: React.ReactNode
27
27
  /** direction of the dropdown */
28
28
  dir?: 'bottom-left'|'bottom-right'|'top-left'|'top-right'
29
+ /** Calendar props */
30
+ DayPickerProps?: DayPickerProps
29
31
  }
30
32
 
31
33
  // An array is returned for mode = 'multiple' or 'range'
@@ -54,6 +56,7 @@ export function FieldDate({
54
56
  prefix = '',
55
57
  showTime,
56
58
  value: valueProp,
59
+ DayPickerProps,
57
60
  ...props
58
61
  }: FieldDateProps) {
59
62
  const localePattern = `d MMM yyyy${showTime && mode == 'single' ? ' hh:mmaa' : ''}`
@@ -146,10 +149,11 @@ export function FieldDate({
146
149
  <div className="flex">
147
150
  <Calendar
148
151
  // Calendar actually accepts an array of dates, but the type is not typed correctly
149
- {...{ mode: mode, value: dates as any, numberOfMonths: numberOfMonths, month: month }}
152
+ {...{ mode: mode, value: dates as any, numberOfMonths: numberOfMonths, month: month }}
153
+ {...DayPickerProps}
150
154
  preserveTime={!!showTime}
151
155
  onChange={onCalendarChange}
152
- className="pt-1 pb-2 px-3"
156
+ className="pt-1 pb-2 px-3"
153
157
  />
154
158
  {!!showTime && mode == 'single' && <TimePicker date={dates?.[0]} onChange={onCalendarChange} />}
155
159
  </div>
@@ -18,6 +18,7 @@ type StyleguideProps = {
18
18
  className?: string
19
19
  elements?: { Button?: typeof ButtonNitro }
20
20
  children?: React.ReactNode
21
+ currencies?: { [key: string]: { name: string, symbol: string, digits: number } }
21
22
  }
22
23
 
23
24
  type QuoteExample = {
@@ -29,7 +30,7 @@ type QuoteExample = {
29
30
  status: string
30
31
  }
31
32
 
32
- export function Styleguide({ className, elements, children }: StyleguideProps) {
33
+ export function Styleguide({ className, elements, children, currencies }: StyleguideProps) {
33
34
  const Button = elements?.Button || ButtonNitro
34
35
  const [, setStore] = useTracked()
35
36
  const [customerSearch, setCustomerSearch] = useState('')
@@ -40,7 +41,7 @@ export function Styleguide({ className, elements, children }: StyleguideProps) {
40
41
  brandColor: '#F3CA5F',
41
42
  colorsMulti: ['blue', 'green'],
42
43
  country: 'nz',
43
- currency: 'nzd', // can be commented too
44
+ currency: 'nzd',
44
45
  date: Date.now(),
45
46
  'date-range': [Date.now(), Date.now() + 1000 * 60 * 60 * 24 * 33],
46
47
  'date-time': Date.now(),
@@ -351,7 +352,7 @@ export function Styleguide({ className, elements, children }: StyleguideProps) {
351
352
  name="country"
352
353
  mode="country"
353
354
  state={state}
354
- options={useMemo(() => getCountryOptions(injectedConfig.countries), [])}
355
+ options={useMemo(() => [{ value: 'nz', label: 'New Zealand' }, { value: 'au', label: 'Australia' }], [])}
355
356
  onChange={(e) => onChange(setState, e)}
356
357
  />
357
358
  </div>
@@ -384,11 +385,11 @@ export function Styleguide({ className, elements, children }: StyleguideProps) {
384
385
  />
385
386
  </div>
386
387
  <div>
387
- <label for="currency">Currencies (Error)</label>
388
+ <label for="currency">Currencies</label>
388
389
  <Select
389
390
  name="currency"
390
391
  state={state}
391
- options={useMemo(() => getCurrencyOptions(injectedConfig.currencies), [])}
392
+ options={useMemo(() => (currencies ? getCurrencyOptions(currencies) : [{ value: 'nzd', label: 'New Zealand Dollar' }, { value: 'aud', label: 'Australian Dollar' }]), [])}
392
393
  onChange={(e) => onChange(setState, e)}
393
394
  />
394
395
  </div>
@@ -433,8 +434,12 @@ export function Styleguide({ className, elements, children }: StyleguideProps) {
433
434
  </div>
434
435
  <div>
435
436
  <label for="amount">Amount ({state.amount})</label>
436
- <Field name="amount" type="currency" state={state} currency={state.currency || 'nzd'} onChange={(e) => onChange(setState, e)}
437
- config={injectedConfig} />
437
+ <Field
438
+ name="amount" type="currency" state={state} currency={state.currency || 'nzd'} onChange={(e) => onChange(setState, e)}
439
+ // Example of using a custom format and currencies, e.g.
440
+ format={'¤#,##0.00'}
441
+ currencies={currencies}
442
+ />
438
443
  </div>
439
444
  </div>
440
445
 
@@ -445,8 +450,18 @@ export function Styleguide({ className, elements, children }: StyleguideProps) {
445
450
  <Field name="date-time" type="date" mode="single" showTime={true} state={state} onChange={(e) => onChange(setState, e)} />
446
451
  </div>
447
452
  <div>
448
- <label for="date-range">Date range with prefix</label>
449
- <Field name="date-range" type="date" mode="range" prefix="Date:" state={state} onChange={(e) => onChange(setState, e)} />
453
+ <label for="date-range">Date range (with prefix & disabled days)</label>
454
+ <Field
455
+ name="date-range"
456
+ type="date"
457
+ mode="range"
458
+ prefix="Date:"
459
+ state={state}
460
+ onChange={(e) => onChange(setState, e)}
461
+ DayPickerProps={{
462
+ disabled: { after: new Date(Date.now() + 1000 * 60 * 60 * 24 * 45) }
463
+ }}
464
+ />
450
465
  </div>
451
466
  <div>
452
467
  <label for="date">Date multi-select (right aligned)</label>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nitro-web",
3
- "version": "0.0.108",
3
+ "version": "0.0.109",
4
4
  "repository": "github:boycce/nitro-web",
5
5
  "homepage": "https://boycce.github.io/nitro-web/",
6
6
  "description": "Nitro is a battle-tested, modular base project to turbocharge your projects, styled using Tailwind 🚀",
package/types.ts CHANGED
@@ -3,8 +3,6 @@
3
3
  type InjectedConfig = {
4
4
  awsUrl?: string
5
5
  clientUrl: string
6
- countries: { [key: string]: { name: string, numberFormats: { currency: string } } } // for input-currency.tsx
7
- currencies: { [key: string]: { name: string, symbol: string, digits: number } } // for input-currency.tsx
8
6
  env: string
9
7
  googleMapsApiKey?: string
10
8
  isDemo: boolean // implicitly defined by webpack