nitro-web 0.2.11 → 0.2.13
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/components/auth/auth.api.js +3 -2
- package/components/partials/form/field-currency.tsx +48 -14
- package/components/partials/form/field.tsx +9 -2
- package/components/partials/styleguide.tsx +12 -3
- package/package.json +2 -2
- package/server/email/index.js +2 -2
- package/{components/auth → tests}/auth.api.test.js +2 -1
- package/types/components/auth/auth.api.d.ts.map +1 -1
- package/types/server/email/index.d.ts +2 -2
|
@@ -739,8 +739,9 @@ export function resolveBaseUrl(reqUrl, cfgUrl) {
|
|
|
739
739
|
try {
|
|
740
740
|
const reqHost = new URL(reqUrl).hostname
|
|
741
741
|
const cfgHost = new URL(cfgUrl).hostname
|
|
742
|
-
|
|
743
|
-
const
|
|
742
|
+
// tldts treats "localhost" as an unknown suffix, so we add an override
|
|
743
|
+
const reqApex = /(^|\.)localhost$/.test(reqHost) ? 'localhost' : getDomain(reqHost)
|
|
744
|
+
const cfgApex = /(^|\.)localhost$/.test(cfgHost) ? 'localhost' : getDomain(cfgHost)
|
|
744
745
|
const errorMessage = 'Nitro warning: auth.resolveBaseUrl: The request origin and the config baseUrl ' +
|
|
745
746
|
'are not the same apex domain. Defaulting to the Cfg baseUrl. Req:'
|
|
746
747
|
|
|
@@ -22,8 +22,14 @@ export type FieldCurrencyProps = Omit<NumericFormatProps, 'onChange' | 'value' |
|
|
|
22
22
|
name: string
|
|
23
23
|
/** name is applied if id is not provided */
|
|
24
24
|
id?: string
|
|
25
|
-
/** currency
|
|
26
|
-
|
|
25
|
+
/** render as a percent field: no currency symbol, '%' suffix */
|
|
26
|
+
percent?: boolean
|
|
27
|
+
/** minimum decimal places to show (percent only; defaults to 0) */
|
|
28
|
+
minDecimals?: number
|
|
29
|
+
/** maximum decimal places to show (percent only; defaults to 2) */
|
|
30
|
+
maxDecimals?: number
|
|
31
|
+
/** currency iso, e.g. 'nzd' (defaults to 'nzd'; ignored when percent) */
|
|
32
|
+
currency?: string
|
|
27
33
|
/** override the default currencies array used to lookup currency symbol and digits, e.g. {nzd: { symbol: '$', digits: 2 }} */
|
|
28
34
|
currencies?: Currencies,
|
|
29
35
|
/** override the default CLDR country currency format, e.g. '¤#,##0.00' */
|
|
@@ -34,10 +40,14 @@ export type FieldCurrencyProps = Omit<NumericFormatProps, 'onChange' | 'value' |
|
|
|
34
40
|
defaultValue?: Cents // defined to just fix typescript error
|
|
35
41
|
}
|
|
36
42
|
|
|
37
|
-
export function FieldCurrency({
|
|
43
|
+
export function FieldCurrency({
|
|
44
|
+
currency='nzd', currencies, format, percent, minDecimals, maxDecimals, onChange: onChangeProp, ...props
|
|
45
|
+
}: FieldCurrencyProps) {
|
|
38
46
|
const [dontFix, setDontFix] = useState(false)
|
|
39
47
|
const [lastBlurred, setLastBlurred] = useState(0)
|
|
40
|
-
const [settings, setSettings] = useState(() =>
|
|
48
|
+
const [settings, setSettings] = useState(() => (
|
|
49
|
+
getCurrencySettings(currency, currencies, format, props.name, percent, minDecimals, maxDecimals)
|
|
50
|
+
))
|
|
41
51
|
const [prefixWidth, setPrefixWidth] = useState(0)
|
|
42
52
|
const [inputPaddingLeft, setInputPaddingLeft] = useState(12)
|
|
43
53
|
const ref = useRef({ dontFix }) // was null
|
|
@@ -64,30 +74,36 @@ export function FieldCurrency({ currency='nzd', currencies, format, onChange: on
|
|
|
64
74
|
|
|
65
75
|
// Update the settings if the setting parameters change
|
|
66
76
|
useEffect(() => {
|
|
67
|
-
const _settings = getCurrencySettings(currency, currencies, format, props.name)
|
|
77
|
+
const _settings = getCurrencySettings(currency, currencies, format, props.name, percent, minDecimals, maxDecimals)
|
|
68
78
|
if (settings.key !== _settings.key) setSettings(_settings)
|
|
69
|
-
}, [currency, currencies, format])
|
|
79
|
+
}, [currency, currencies, format, percent, minDecimals, maxDecimals])
|
|
70
80
|
|
|
71
81
|
// Get the prefix content width
|
|
72
82
|
useEffect(() => {
|
|
73
83
|
setPrefixWidth(settings.prefix ? getPrefixWidth(settings.prefix, 1) : 0)
|
|
74
84
|
}, [settings.prefix])
|
|
75
85
|
|
|
76
|
-
function to(type: 'dollars' | 'cents', value?: Cents, settings?: { maxDecimals?: number }) {
|
|
86
|
+
function to(type: 'dollars' | 'cents', value?: Cents, settings?: { maxDecimals?: number, minDecimals?: number }) {
|
|
77
87
|
const maxDecimals = settings?.maxDecimals
|
|
88
|
+
const minDecimals = Math.min(settings?.minDecimals ?? 0, maxDecimals ?? 0)
|
|
78
89
|
const parsed = parseFloat(value + '')
|
|
79
90
|
if (!parsed && parsed !== 0) return null
|
|
80
91
|
if (!maxDecimals) return parsed
|
|
81
92
|
|
|
82
|
-
const value2 = type === 'dollars'
|
|
83
|
-
? parsed / Math.pow(10, maxDecimals)
|
|
93
|
+
const value2 = type === 'dollars'
|
|
94
|
+
? parsed / Math.pow(10, maxDecimals)
|
|
84
95
|
: parsed * Math.pow(10, maxDecimals) // e.g. 1.23 => 123
|
|
85
96
|
|
|
86
97
|
// dont fix when the user is typing.
|
|
87
98
|
if (type === 'dollars' && ref.current.dontFix) { setDontFix(false) }
|
|
88
99
|
|
|
89
|
-
|
|
90
|
-
|
|
100
|
+
if (type === 'cents' || ref.current.dontFix || !minDecimals) return value2
|
|
101
|
+
|
|
102
|
+
// pad to maxDecimals then trim trailing zeros back down to (at least) minDecimals
|
|
103
|
+
const [whole, decimals=''] = value2.toFixed(maxDecimals).split('.')
|
|
104
|
+
let trimmed = decimals
|
|
105
|
+
while (trimmed.length > minDecimals && trimmed.endsWith('0')) trimmed = trimmed.slice(0, -1)
|
|
106
|
+
return trimmed ? `${whole}.${trimmed}` : whole
|
|
91
107
|
}
|
|
92
108
|
|
|
93
109
|
function onChange(source: 'event' | 'prop', floatValue?: number) {
|
|
@@ -96,6 +112,10 @@ export function FieldCurrency({ currency='nzd', currencies, format, onChange: on
|
|
|
96
112
|
else setInternalValue(to('cents', floatValue, settings))
|
|
97
113
|
}
|
|
98
114
|
|
|
115
|
+
useEffect(() => {
|
|
116
|
+
console.log('settings', settings)
|
|
117
|
+
}, [settings])
|
|
118
|
+
|
|
99
119
|
return (
|
|
100
120
|
<div className="relative">
|
|
101
121
|
<NumericFormat
|
|
@@ -110,6 +130,7 @@ export function FieldCurrency({ currency='nzd', currencies, format, onChange: on
|
|
|
110
130
|
onBlur={() => { setLastBlurred(Date.now())}}
|
|
111
131
|
placeholder={props.placeholder || '0.00'}
|
|
112
132
|
value={inputValue}
|
|
133
|
+
suffix={settings.suffix}
|
|
113
134
|
style={{ textIndent: `${prefixWidth}px` }}
|
|
114
135
|
type="text"
|
|
115
136
|
/>
|
|
@@ -117,15 +138,28 @@ export function FieldCurrency({ currency='nzd', currencies, format, onChange: on
|
|
|
117
138
|
class={`absolute top-0 bottom-0 inline-flex items-center select-none text-gray-500 text-input-base ${inputValue !== null && settings.prefix == '$' ? 'text-foreground' : ''}`}
|
|
118
139
|
style={{ left: `${inputPaddingLeft}px` }}
|
|
119
140
|
>
|
|
120
|
-
{settings.prefix
|
|
141
|
+
{settings.prefix}
|
|
121
142
|
</span>
|
|
122
143
|
</div>
|
|
123
144
|
)
|
|
124
145
|
}
|
|
125
146
|
|
|
126
|
-
function getCurrencySettings(
|
|
147
|
+
function getCurrencySettings(
|
|
148
|
+
currency: string, currencies?: Currencies, format?: string, name?: string, percent?: boolean,
|
|
149
|
+
minDecimals?: number, maxDecimals?: number
|
|
150
|
+
) {
|
|
151
|
+
// percent reuses the currency machinery but with a '%' suffix and no currency lookup
|
|
152
|
+
if (percent) {
|
|
153
|
+
const _minDecimals = minDecimals ?? 0
|
|
154
|
+
const _maxDecimals = maxDecimals ?? 2
|
|
155
|
+
return {
|
|
156
|
+
key: `percent:${_minDecimals}:${_maxDecimals}`, currency: currency, decimalSeparator: '.', thousandSeparator: ',',
|
|
157
|
+
minDecimals: _minDecimals, maxDecimals: _maxDecimals, prefix: undefined, suffix: '%',
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
127
161
|
// parse CLDR currency string format, e.g. '¤#,##0.00'
|
|
128
|
-
const output: {
|
|
162
|
+
const output: {
|
|
129
163
|
key?: string
|
|
130
164
|
currency: string, // e.g. 'nzd'
|
|
131
165
|
decimalSeparator?: string, // e.g. '.'
|
|
@@ -9,7 +9,7 @@ import { Errors, type Error } from 'nitro-web/types'
|
|
|
9
9
|
import { MailIcon, CalendarIcon, FunnelIcon, SearchIcon, EyeIcon, EyeOffIcon, ClockIcon, PaperclipIcon } from 'lucide-react'
|
|
10
10
|
import { memo, useState } from 'react'
|
|
11
11
|
|
|
12
|
-
type FieldType = 'text' | 'number' | 'password' | 'email' | 'filter' | 'search' | 'textarea' | 'currency' | 'date' | 'color' | 'file'
|
|
12
|
+
type FieldType = 'text' | 'number' | 'password' | 'email' | 'filter' | 'search' | 'textarea' | 'currency' | 'percent' | 'date' | 'color' | 'file'
|
|
13
13
|
type InputProps = React.InputHTMLAttributes<HTMLInputElement>
|
|
14
14
|
type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>
|
|
15
15
|
type FieldExtraProps = {
|
|
@@ -42,6 +42,7 @@ export type FieldProps = (
|
|
|
42
42
|
| ({ type?: 'text' | 'number' | 'password' | 'email' | 'filter' | 'search' } & InputProps & FieldExtraProps)
|
|
43
43
|
| ({ type: 'textarea' } & TextareaProps & FieldExtraProps)
|
|
44
44
|
| ({ type: 'currency' } & FieldCurrencyProps & FieldExtraProps)
|
|
45
|
+
| ({ type: 'percent' } & Omit<FieldCurrencyProps, 'currency'> & FieldExtraProps)
|
|
45
46
|
| ({ type: 'color' } & FieldColorProps & FieldExtraProps)
|
|
46
47
|
| ({ type: 'date' } & FieldDateProps & FieldExtraProps)
|
|
47
48
|
| ({ type: 'file' } & InputProps & FieldExtraProps)
|
|
@@ -140,7 +141,13 @@ function FieldBase({ state, icon, iconPos: ip, errorTitle, inputClassName, ...pr
|
|
|
140
141
|
{Icon}<FieldCurrency {...props} {...commonProps} />
|
|
141
142
|
</FieldContainer>
|
|
142
143
|
)
|
|
143
|
-
} else if (type == '
|
|
144
|
+
} else if (type == 'percent') {
|
|
145
|
+
return (
|
|
146
|
+
<FieldContainer error={error} className={props.className}>
|
|
147
|
+
{Icon}<FieldCurrency {...props} {...commonProps} percent />
|
|
148
|
+
</FieldContainer>
|
|
149
|
+
)
|
|
150
|
+
} else if (type == 'date') {
|
|
144
151
|
return (
|
|
145
152
|
<FieldContainer error={error} className={props.className}>
|
|
146
153
|
<FieldDate {...props} {...commonProps} Icon={Icon} />
|
|
@@ -69,6 +69,7 @@ export function Styleguide({ className, elements, children, currencies, groups }
|
|
|
69
69
|
colorsMulti: ['blue', 'green'],
|
|
70
70
|
country: 'cd',
|
|
71
71
|
currency: 'nzd',
|
|
72
|
+
percent: 1250,
|
|
72
73
|
customer: '1',
|
|
73
74
|
date: Date.now(),
|
|
74
75
|
dateRange: [Date.now(), Date.now() + 1000 * 60 * 60 * 24 * 33],
|
|
@@ -89,7 +90,8 @@ export function Styleguide({ className, elements, children, currencies, groups }
|
|
|
89
90
|
brandColor: '#8656ED',
|
|
90
91
|
colorsMulti: ['blue'],
|
|
91
92
|
country: 'au',
|
|
92
|
-
currency: 'btc',
|
|
93
|
+
currency: 'btc',
|
|
94
|
+
percent: 875,
|
|
93
95
|
date: Date.now() + 1000 * 60 * 60 * 24 * 1.2,
|
|
94
96
|
dateRange: [Date.now(), Date.now() + 1000 * 60 * 60 * 24 * 5.2],
|
|
95
97
|
dateMultiple: [Date.now(), Date.now() + 1000 * 60 * 60 * 24 * 3.2],
|
|
@@ -223,7 +225,7 @@ export function Styleguide({ className, elements, children, currencies, groups }
|
|
|
223
225
|
options={[
|
|
224
226
|
{ label: 'Set Status', onClick: () => { console.log('set', row._id) } },
|
|
225
227
|
{ label: 'Delete', onClick: () => { console.log('remove', row._id) } },
|
|
226
|
-
]}
|
|
228
|
+
]}
|
|
227
229
|
dir={rows.slice(0, perPage).length - 3 < i ? 'top-right' : 'bottom-right'}
|
|
228
230
|
minWidth={100}
|
|
229
231
|
>
|
|
@@ -583,13 +585,20 @@ export function Styleguide({ className, elements, children, currencies, groups }
|
|
|
583
585
|
<div>
|
|
584
586
|
<label for="amount">Amount ({state.amount})</label>
|
|
585
587
|
<Field
|
|
586
|
-
name="amount"
|
|
588
|
+
name="amount"
|
|
589
|
+
type="currency"
|
|
590
|
+
state={state}
|
|
591
|
+
currency={state.currency || 'nzd'}
|
|
587
592
|
// Example of using a custom format and currencies, e.g.
|
|
588
593
|
format={'¤#,##0.00'}
|
|
589
594
|
currencies={currencies}
|
|
590
595
|
onChange={(e) => onChange(e, setState)}
|
|
591
596
|
/>
|
|
592
597
|
</div>
|
|
598
|
+
<div>
|
|
599
|
+
<label for="percent">Percent ({state.percent})</label>
|
|
600
|
+
<Field name="percent" type="percent" state={state} onChange={(e) => onChange(e, setState)} minDecimals={1} maxDecimals={4} />
|
|
601
|
+
</div>
|
|
593
602
|
<div>
|
|
594
603
|
<label for="firstName">First Name (disabled)</label>
|
|
595
604
|
<Field name="firstName" state={state} onChange={(e) => onChange(e, setState)} disabled />
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nitro-web",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.13",
|
|
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 🚀",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"minor": "npm run types && standard-version -a --release-as minor && npm publish && cd ../webpack && npm publish",
|
|
32
32
|
"patch": "npm run types && standard-version -a --release-as patch && npm publish && cd ../webpack && npm publish",
|
|
33
33
|
"republish": "npm publish && cd ../webpack && npm publish",
|
|
34
|
-
"test": "node --test
|
|
34
|
+
"test": "node --test tests/",
|
|
35
35
|
"types": "tsc util.js ./server/index.js --declaration --declarationMap --allowJs --emitDeclarationOnly --jsx react-jsx --esModuleInterop --skipLibCheck --outDir types && cd ../webpack && npm run types -w . && cd ../core"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
package/server/email/index.js
CHANGED
|
@@ -26,8 +26,8 @@ export const optionalEmailConfigKeys = ['emailReplyTo', 'emailTestMode', 'mailgu
|
|
|
26
26
|
* @param {string} opts.to - Recipient(s), e.g. "Bruce<bruce@wayneenterprises.com>,..."
|
|
27
27
|
* @param {Config} opts.config - Config object
|
|
28
28
|
* @param {string} [opts.bcc] - BCC, e.g. "Bruce<bruce@wayneenterprises.com>" (not sent in development)
|
|
29
|
-
* @param {object} [opts.data] - template data shared across recipients
|
|
30
|
-
* @param {object} [opts.swigData] - vars for Nunjucks/Swig render only (not sent to Mailgun)
|
|
29
|
+
* @param {object} [opts.data] - common template data shared across recipients
|
|
30
|
+
* @param {object} [opts.swigData] - vars for Nunjucks/Swig render only (not sent to Mailgun). Inherits data.
|
|
31
31
|
* @param {string} [opts.from] - sender address, e.g. "Bruce<bruce@wayneenterprises.com>"
|
|
32
32
|
* @param {string} [opts.replyTo] - reply-to address, e.g. "Bruce<bruce@wayneenterprises.com>"
|
|
33
33
|
* @param {object} [opts.recipientVariables] - Mailgun recipient-variables for batch sending
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { test } from 'node:test'
|
|
2
2
|
import assert from 'node:assert/strict'
|
|
3
|
-
import { resolveBaseUrl } from '
|
|
3
|
+
import { resolveBaseUrl } from '../components/auth/auth.api.js'
|
|
4
4
|
|
|
5
5
|
const cases = [
|
|
6
6
|
// [cfgUrl, reqUrl, expected, description]
|
|
@@ -16,6 +16,7 @@ const cases = [
|
|
|
16
16
|
|
|
17
17
|
['http://localhost:3000', 'http://localhost:3001', 'http://localhost:3001', 'match: localhost: port (ignored)'],
|
|
18
18
|
['http://localhost:3000', 'http://app.localhost:3001', 'http://app.localhost:3001', 'match: localhost: nested'],
|
|
19
|
+
['http://app.localhost:3000', 'http://app2.localhost:3001', 'http://app2.localhost:3001', 'match: localhost: sibling'],
|
|
19
20
|
['http://127.0.0.1:3000', 'http://127.0.0.1:3000', 'http://127.0.0.1:3000', 'match: IP exact'],
|
|
20
21
|
|
|
21
22
|
// cfg: mismatch
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.api.d.ts","sourceRoot":"","sources":["../../../components/auth/auth.api.js"],"names":[],"mappings":"AAqLA,qEAUC;AAED,qEAwEC;AAED,qEAGC;AAED,gEAMC;AAED,iEAgBC;AAED,oEAGC;AAED,oEA8BC;AAED,gEAgCC;AAID,qGAkDC;AAED;;;GAOC;AAED;;GAKC;AAID;;;;;;;;;GASG;AACH,8EAPG;IAA0B,QAAQ,GAA1B,MAAM;IACY,SAAS,GAA3B,MAAM;IACY,OAAO,GAAzB,MAAM;CACd,YAAQ,MAAM,+BACN,OAAO,GACL,OAAO,CAAC,MAAM,CAAC,CAqE3B;AAED,kFAiBC;AAED,mEAOC;AAED,+EAWC;AAED,sHAiBC;AAED;;;GAEC;AAED;;;GA0BC;AAED;;;;;;;;;GAmCC;AAED;;;;;;;;;;;;;;GAcG;AACH,mGAZG;IAAsD,IAAI,EAAlD,OAAO,GAAG,QAAQ,GAAG,eAAe;IACpB,EAAE,EAAlB,MAAM;IAKH,OAAO,EAJV;QACN,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,EAAE,MAAM,CAAC;QACtB,CAAK,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACpB;IAC0B,YAAY;IACZ,eAAe;IACjB,OAAO,GAAxB,MAAM;CACd,GAAU,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;CAAC,CAAC,CAmEtE;AAED,0CAEC;AAED,
|
|
1
|
+
{"version":3,"file":"auth.api.d.ts","sourceRoot":"","sources":["../../../components/auth/auth.api.js"],"names":[],"mappings":"AAqLA,qEAUC;AAED,qEAwEC;AAED,qEAGC;AAED,gEAMC;AAED,iEAgBC;AAED,oEAGC;AAED,oEA8BC;AAED,gEAgCC;AAID,qGAkDC;AAED;;;GAOC;AAED;;GAKC;AAID;;;;;;;;;GASG;AACH,8EAPG;IAA0B,QAAQ,GAA1B,MAAM;IACY,SAAS,GAA3B,MAAM;IACY,OAAO,GAAzB,MAAM;CACd,YAAQ,MAAM,+BACN,OAAO,GACL,OAAO,CAAC,MAAM,CAAC,CAqE3B;AAED,kFAiBC;AAED,mEAOC;AAED,+EAWC;AAED,sHAiBC;AAED;;;GAEC;AAED;;;GA0BC;AAED;;;;;;;;;GAmCC;AAED;;;;;;;;;;;;;;GAcG;AACH,mGAZG;IAAsD,IAAI,EAAlD,OAAO,GAAG,QAAQ,GAAG,eAAe;IACpB,EAAE,EAAlB,MAAM;IAKH,OAAO,EAJV;QACN,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,EAAE,MAAM,CAAC;QACtB,CAAK,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACpB;IAC0B,YAAY;IACZ,eAAe;IACjB,OAAO,GAAxB,MAAM;CACd,GAAU,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;CAAC,CAAC,CAmEtE;AAED,0CAEC;AAED,8DA8BC;AAED,gFAKC;;;;;;;;;;;;;;;;;;;;AA1uBD;;;;;;;;;;;;;;;EAiBC;AA0ED,0DAEC;AAgCD,mDAEC;AAtBD,iDAkBC;AA5BD,2DAQC;AA0BD,2DAwBC;AAtID,0EAsEC"}
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* @param {string} opts.to - Recipient(s), e.g. "Bruce<bruce@wayneenterprises.com>,..."
|
|
8
8
|
* @param {Config} opts.config - Config object
|
|
9
9
|
* @param {string} [opts.bcc] - BCC, e.g. "Bruce<bruce@wayneenterprises.com>" (not sent in development)
|
|
10
|
-
* @param {object} [opts.data] - template data shared across recipients
|
|
11
|
-
* @param {object} [opts.swigData] - vars for Nunjucks/Swig render only (not sent to Mailgun)
|
|
10
|
+
* @param {object} [opts.data] - common template data shared across recipients
|
|
11
|
+
* @param {object} [opts.swigData] - vars for Nunjucks/Swig render only (not sent to Mailgun). Inherits data.
|
|
12
12
|
* @param {string} [opts.from] - sender address, e.g. "Bruce<bruce@wayneenterprises.com>"
|
|
13
13
|
* @param {string} [opts.replyTo] - reply-to address, e.g. "Bruce<bruce@wayneenterprises.com>"
|
|
14
14
|
* @param {object} [opts.recipientVariables] - Mailgun recipient-variables for batch sending
|