@ultraviolet/plus 0.5.0 → 0.5.2

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/dist/index.d.ts CHANGED
@@ -3,6 +3,9 @@ import { ReactNode, MouseEventHandler, ComponentProps } from 'react';
3
3
  import * as _emotion_react_jsx_runtime from '@emotion/react/jsx-runtime';
4
4
  import { langs } from '@uiw/codemirror-extensions-langs';
5
5
  import CodeMirror from '@uiw/react-codemirror';
6
+ import { Alert } from '@ultraviolet/ui';
7
+ import * as _emotion_styled from '@emotion/styled';
8
+ import * as _emotion_react from '@emotion/react';
6
9
 
7
10
  type ContentCardProps = {
8
11
  direction?: 'row' | 'column';
@@ -62,4 +65,261 @@ type CodeEditorProps = {
62
65
  };
63
66
  declare const CodeEditor: ({ title, value, onChange, extensions, onBlur, height, readOnly, }: CodeEditorProps) => _emotion_react_jsx_runtime.JSX.Element;
64
67
 
65
- export { CodeEditor, ContentCard, ContentCardGroup };
68
+ declare const _default: {
69
+ readonly 'estimate.cost.description': "This summary provides a cost estimation based on your configuration, the amount of time you expect to use the resource for, and the scale of your expected usage. For the purposes of this calculation, we consider that 1 month equals to 730 hours.";
70
+ readonly 'estimate.cost.label': "Estimated cost";
71
+ readonly 'estimate.cost.beta.free': "Free During Beta";
72
+ readonly 'estimate.cost.beta.discount': "% off during Beta";
73
+ readonly 'estimate.cost.beta.badge': "Beta Version";
74
+ readonly 'estimate.cost.units.seconds.label': "Second(s)";
75
+ readonly 'estimate.cost.units.minutes.label': "Minute(s)";
76
+ readonly 'estimate.cost.units.hours.label': "Hour(s)";
77
+ readonly 'estimate.cost.units.days.label': "Day(s)";
78
+ readonly 'estimate.cost.units.months.label': "Month(s)";
79
+ readonly 'estimate.cost.units.years.label': "Year(s)";
80
+ readonly 'estimate.cost.fees.oneTime.title': "One time fees";
81
+ readonly 'estimate.cost.fees.monthly.title': "Each month";
82
+ readonly 'estimate.cost.fees.commitment': "Commitment Fees";
83
+ readonly 'estimate.cost.units.gb.label': "GB";
84
+ readonly 'estimate.cost.notDefined': "Not defined";
85
+ readonly 'estimate.cost.submit.label': "Create";
86
+ readonly 'estimate.cost.region.label': "Region";
87
+ readonly 'estimate.cost.az.label': "Availability Zone";
88
+ };
89
+
90
+ type EstimateCostProps = {
91
+ /**
92
+ * Text to display into an alert on the top of the EstimateCost component.
93
+ */
94
+ alert?: ReactNode;
95
+ /**
96
+ * Type of the alert defined by the Scaleway UI Alert component.
97
+ */
98
+ alertVariant?: ComponentProps<typeof Alert>['sentiment'];
99
+ children: ReactNode;
100
+ /**
101
+ * Individual fees to display at the bottom of the EstimateCost component.
102
+ */
103
+ commitmentFees?: number;
104
+ /**
105
+ * Content to display into the fees part, it can be any component but in order to have a consistent design, it is recommended to use `<EstimateCost.Regular>` and `<EstimateCost.Strong>` components.
106
+ */
107
+ commitmentFeesContent?: ReactNode;
108
+ /**
109
+ * By default, a description exists but if you need you can customize it with this prop.
110
+ */
111
+ description?: ReactNode;
112
+ /**
113
+ * Hide the floating estimate cost overlay shown in the bottom of the page.
114
+ */
115
+ hideOverlay?: boolean;
116
+ /**
117
+ * Disable left button on the overlay.
118
+ */
119
+ disableOverlayLeft?: boolean;
120
+ /**
121
+ * Disable right button (submit) on the overlay.
122
+ */
123
+ disableOverlayRight?: boolean;
124
+ /**
125
+ * This is a global discount for all estimate cost, all sub items will be impacted by this discount.
126
+ * The discount is a percentage, so 0.1 means 10% discount. Discount = 1 means 100% so it means free.
127
+ * This is usually associate with beta products and prop `isBeta`.
128
+ */
129
+ discount?: number;
130
+ /**
131
+ * The default time unit to select.
132
+ */
133
+ defaultTimeUnit?: Units;
134
+ /**
135
+ * List of time unit the price can be calculated with. Can only be an array of `seconds`, `minutes`, `hours`, `days` or `months`.
136
+ */
137
+ timeUnits?: Units[];
138
+ /**
139
+ * Hide the selectable time unit on the top of the component.
140
+ */
141
+ hideTimeUnit?: boolean;
142
+ /**
143
+ * Hide the total price at the bottom of the component.
144
+ */
145
+ hideTotal?: boolean;
146
+ /**
147
+ * Show a badge beta on the total price with how much discount is applied.
148
+ */
149
+ isBeta?: boolean;
150
+ /**
151
+ * It will display another individual line at the bottom of the component with a monthly price. It can be used when you display hourly price, but you have one or many items that are billed monthly.
152
+ */
153
+ monthlyFees?: number;
154
+ /**
155
+ * Content to display into monthly fees part, it can be any component but in order to have a consistent design, it is recommended to use `<EstimateCost.Regular>` and `<EstimateCost.Strong>` components.
156
+ */
157
+ monthlyFeesContent?: ReactNode;
158
+ /**
159
+ * Label of the item, it describes what kind of fees is related to. (ex: "Installation fee")
160
+ */
161
+ monthlyFeesLabel?: string;
162
+ /**
163
+ * Content that will be shown on the left side of the overlay.
164
+ */
165
+ OverlayLeft?: (props: {
166
+ children: ReactNode;
167
+ disabled?: boolean;
168
+ }) => JSX.Element;
169
+ /**
170
+ * Content that will be shown on the left side of the overlay.
171
+ */
172
+ OverlayRight?: (props: {
173
+ children?: ReactNode;
174
+ disabled?: boolean;
175
+ }) => JSX.Element;
176
+ /**
177
+ * Time unit to use on the overlay. It can be different from estimate cost.
178
+ */
179
+ overlayUnit?: Units;
180
+ /**
181
+ * Locales for the component. By default, it will use the english locales.
182
+ */
183
+ locales?: typeof _default;
184
+ /**
185
+ * Defines the currency to be shown in the component.
186
+ * To find out all currencies checkout https://en.wikipedia.org/wiki/ISO_4217#List_of_ISO_4217_currency_codes section "Code" of the table.
187
+ */
188
+ currency?: string;
189
+ /**
190
+ * Defines the way we display numbers depending on locale (ex: 1,000.00 or 1 000,00).
191
+ * To understand better please read https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#locales
192
+ */
193
+ numberLocales?: string;
194
+ };
195
+ type Units = 'seconds' | 'minutes' | 'hours' | 'days' | 'months';
196
+ type Iteration = {
197
+ unit: Units;
198
+ value: number;
199
+ };
200
+ type BareEstimateProduct = {
201
+ id: string;
202
+ };
203
+ type EstimateProduct = BareEstimateProduct & {
204
+ amount: number;
205
+ price: number;
206
+ amountFree: number;
207
+ isVariant: boolean;
208
+ maxAmount: number;
209
+ noIteration: boolean;
210
+ longFractionDigits: boolean;
211
+ discount: number;
212
+ };
213
+
214
+ declare const EstimateCost: {
215
+ ({ description, alert, alertVariant, defaultTimeUnit, timeUnits, hideOverlay, disableOverlayLeft, disableOverlayRight, hideTimeUnit, hideTotal, discount, OverlayRight, OverlayLeft, isBeta, commitmentFees, commitmentFeesContent, monthlyFees, monthlyFeesLabel, monthlyFeesContent, overlayUnit, children, locales, numberLocales, currency, }: EstimateCostProps): _emotion_react_jsx_runtime.JSX.Element;
216
+ LineThrough: _emotion_styled.StyledComponent<{
217
+ theme?: _emotion_react.Theme | undefined;
218
+ as?: react.ElementType<any> | undefined;
219
+ } & {
220
+ isActive?: boolean | undefined;
221
+ }, react.DetailedHTMLProps<react.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, {}>;
222
+ Item: ({ discount, priceText, discountText, label, tooltipInfo, subLabel, price: basePrice, monthlyPrice, unit: baseUnit, amount: currentAmount, onAmountChange, amountFree, maxAmount, longFractionDigits, noIteration, noIterationText, noBorder, noPrice, isDefined, children, isFirstElement, isLastElement, isPrimaryBackground, productsCallback, iteration: receivedIteration, shouldBeHidden, hideFromOverlay, textNotDefined, animated, tabulation, labelTextVariant, labelTextProminence, notice, }: {
223
+ amount?: number | undefined;
224
+ amountFree?: number | undefined;
225
+ animated?: boolean | undefined;
226
+ children?: ReactNode;
227
+ discount?: number | undefined;
228
+ discountText?: string | undefined;
229
+ hideFromOverlay?: boolean | undefined;
230
+ isDefined?: boolean | undefined;
231
+ isFirstElement?: boolean | undefined;
232
+ isLastElement?: boolean | undefined;
233
+ isPrimaryBackground?: boolean | undefined;
234
+ iteration?: Iteration | undefined;
235
+ label?: ReactNode;
236
+ labelTextVariant?: "body" | "caption" | "code" | "heading" | "bodySmall" | "bodySmallStrong" | "bodySmallStronger" | "bodyStrong" | "bodyStronger" | "captionSmall" | "captionSmallStrong" | "captionSmallStronger" | "captionStrong" | "captionStronger" | "headingLarge" | "headingSmall" | undefined;
237
+ labelTextProminence?: "strong" | "default" | "stronger" | "weak" | undefined;
238
+ longFractionDigits?: boolean | undefined;
239
+ maxAmount?: number | undefined;
240
+ monthlyPrice?: number | undefined;
241
+ noBorder?: boolean | undefined;
242
+ noIteration?: boolean | undefined;
243
+ noIterationText?: string | undefined;
244
+ noPrice?: boolean | undefined;
245
+ notice?: string | undefined;
246
+ onAmountChange?: ((amount: number) => void) | undefined;
247
+ price?: number | undefined;
248
+ priceText?: ReactNode;
249
+ productsCallback?: {
250
+ add: (product: EstimateProduct) => void;
251
+ remove: (product: BareEstimateProduct) => void;
252
+ } | undefined;
253
+ shouldBeHidden?: boolean | undefined;
254
+ subLabel?: string | undefined;
255
+ tabulation?: number | undefined;
256
+ textNotDefined?: string | undefined;
257
+ tooltipInfo?: string | undefined;
258
+ unit?: (string & {}) | "seconds" | "minutes" | "hours" | "days" | "months" | "mb" | "gb" | "tb" | "years" | undefined;
259
+ }) => _emotion_react_jsx_runtime.JSX.Element;
260
+ NumberInput: ({ amount, minValue, maxValue, getAmountValue, itemCallback, }: {
261
+ amount?: number | undefined;
262
+ itemCallback?: ((amount?: number | undefined, isVariant?: boolean | undefined) => void) | undefined;
263
+ getAmountValue?: ((amount?: number | undefined) => void) | undefined;
264
+ minValue?: number | undefined;
265
+ maxValue?: number | undefined;
266
+ }) => _emotion_react_jsx_runtime.JSX.Element;
267
+ Unit: ({ amount, itemCallback, getAmountValue, unit, }: {
268
+ amount?: number | undefined;
269
+ itemCallback?: ((amount?: number | undefined, isVariant?: boolean | undefined) => void) | undefined;
270
+ getAmountValue?: ((amount?: number | undefined) => void) | undefined;
271
+ unit?: string | undefined;
272
+ }) => _emotion_react_jsx_runtime.JSX.Element;
273
+ Strong: ({ variant, children, isDisabledOnOverlay, }: {
274
+ variant?: "big" | "small" | "normal" | "capitalized" | undefined;
275
+ children?: ReactNode;
276
+ isDisabledOnOverlay?: boolean | undefined;
277
+ }) => _emotion_react_jsx_runtime.JSX.Element;
278
+ Regular: ({ variant, isDisabledOnOverlay, children, className, }: {
279
+ variant?: "big" | "small" | "normal" | "capitalized" | undefined;
280
+ isDisabledOnOverlay?: boolean | undefined;
281
+ children?: ReactNode;
282
+ className?: string | undefined;
283
+ }) => _emotion_react_jsx_runtime.JSX.Element | null;
284
+ Image: _emotion_styled.StyledComponent<{
285
+ theme?: _emotion_react.Theme | undefined;
286
+ as?: react.ElementType<any> | undefined;
287
+ }, react.DetailedHTMLProps<react.ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement>, {}>;
288
+ Region: ({ label, image, shouldBeHidden, priceText, animated, isFirstElement, isLastElement, productsCallback, iteration, discount, }: {
289
+ shouldBeHidden?: boolean | undefined;
290
+ priceText?: ReactNode;
291
+ animated?: boolean | undefined;
292
+ isFirstElement?: boolean | undefined;
293
+ isLastElement?: boolean | undefined;
294
+ productsCallback?: {
295
+ add: (product: EstimateProduct) => void;
296
+ remove: (product: BareEstimateProduct) => void;
297
+ } | undefined;
298
+ iteration?: Iteration | undefined;
299
+ discount?: number | undefined;
300
+ label: string;
301
+ image: string;
302
+ }) => _emotion_react_jsx_runtime.JSX.Element;
303
+ Zone: ({ label, image, shouldBeHidden, priceText, animated, isFirstElement, isLastElement, productsCallback, iteration, discount, }: {
304
+ shouldBeHidden?: boolean | undefined;
305
+ priceText?: string | undefined;
306
+ animated?: boolean | undefined;
307
+ isFirstElement?: boolean | undefined;
308
+ isLastElement?: boolean | undefined;
309
+ productsCallback?: {
310
+ add: (product: EstimateProduct) => void;
311
+ remove: (product: BareEstimateProduct) => void;
312
+ } | undefined;
313
+ iteration?: Iteration | undefined;
314
+ discount?: number | undefined;
315
+ label: string;
316
+ image: string;
317
+ }) => _emotion_react_jsx_runtime.JSX.Element;
318
+ Ellipsis: ({ children, maxWidth, "data-testid": dataTestId, }: {
319
+ children: ReactNode;
320
+ maxWidth?: number | undefined;
321
+ 'data-testid'?: string | undefined;
322
+ }) => _emotion_react_jsx_runtime.JSX.Element;
323
+ };
324
+
325
+ export { CodeEditor, ContentCard, ContentCardGroup, EstimateCost, _default as estimateCostDefaultLocales };
@@ -0,0 +1,48 @@
1
+ import { useMemo } from 'react';
2
+ import { useEstimateCost } from '../EstimateCostProvider.js';
3
+ import { UnitInput } from './UnitInput.js';
4
+ import { jsx } from '@emotion/react/jsx-runtime';
5
+
6
+ const CustomUnitInput = _ref => {
7
+ let {
8
+ defaultTimeUnit = 'hours',
9
+ setIteration,
10
+ iteration,
11
+ timeUnits
12
+ } = _ref;
13
+ const {
14
+ locales
15
+ } = useEstimateCost();
16
+ const options = useMemo(() => timeUnits.map(unit => ({
17
+ value: unit,
18
+ label: locales[`estimate.cost.units.${unit}.label`]
19
+ })), [timeUnits, locales]);
20
+ const defaultOption = useMemo(() => options.find(_ref2 => {
21
+ let {
22
+ value
23
+ } = _ref2;
24
+ return value === defaultTimeUnit;
25
+ }), [defaultTimeUnit, options]);
26
+ return jsx(UnitInput, {
27
+ name: "iteration",
28
+ onChange: inputValue => setIteration({
29
+ unit: iteration.unit,
30
+ value: inputValue
31
+ }),
32
+ onChangeUnitValue: unitValue => {
33
+ setIteration({
34
+ unit: unitValue,
35
+ value: iteration.value
36
+ });
37
+ },
38
+ placeholder: "0",
39
+ value: iteration.value,
40
+ unitValue: iteration.unit || defaultOption?.value,
41
+ minValue: 1,
42
+ size: "medium",
43
+ options: options,
44
+ selectInputWidth: 300
45
+ });
46
+ };
47
+
48
+ export { CustomUnitInput };
@@ -0,0 +1,327 @@
1
+ import _styled from '@emotion/styled/base';
2
+ import { css } from '@emotion/react';
3
+ import { Text, Tooltip, Stack, Icon, zoomIn, Badge } from '@ultraviolet/ui';
4
+ import { useMemo, useState, useEffect, useCallback, useId, Children, isValidElement, cloneElement } from 'react';
5
+ import flattenChildren from 'react-flatten-children';
6
+ import { useEstimateCost } from '../EstimateCostProvider.js';
7
+ import { useOverlay } from '../OverlayContext.js';
8
+ import { Cell, StyledDiv, PriceCell, OverlayRow, StyledLeftSide } from '../componentStyle.js';
9
+ import { multiplier, maximumFractionDigitsLong, maximumFractionDigits, MAX_CELL_WIDTH } from '../constants.js';
10
+ import { calculatePrice } from '../helper.js';
11
+ import { jsxs, jsx, Fragment } from '@emotion/react/jsx-runtime';
12
+
13
+ function _EMOTION_STRINGIFIED_CSS_ERROR__() { return "You have tried to stringify object returned from `css` function. It isn't supposed to be used directly (e.g. as value of the `className` prop), but rather handed to emotion so it can handle it (e.g. as value of `css` prop)."; }
14
+ const TIME_RELATED_UNIT = ['seconds', 'minutes', 'hours', 'days', 'months'];
15
+ const StyledResourceName = /*#__PURE__*/_styled('div', {
16
+ shouldForwardProp: prop => !['isOverlay', 'animated'].includes(prop),
17
+ target: "e1kzy2rr7"
18
+ })("text-align:", _ref => {
19
+ let {
20
+ isOverlay
21
+ } = _ref;
22
+ return isOverlay ? 'initial' : 'right';
23
+ }, ";", _ref2 => {
24
+ let {
25
+ isOverlay,
26
+ animated
27
+ } = _ref2;
28
+ return isOverlay ? /*#__PURE__*/css("height:48px;display:flex;flex-direction:column;-webkit-box-pack:center;justify-content:center;animation:", animated ? /*#__PURE__*/css("800ms ", zoomIn, ";") : '', ";") : null;
29
+ }, ";");
30
+ const StyledBadge = /*#__PURE__*/_styled(Badge, {
31
+ target: "e1kzy2rr6"
32
+ })("margin-left:", _ref3 => {
33
+ let {
34
+ theme
35
+ } = _ref3;
36
+ return theme.space['1'];
37
+ }, ";align-self:center;");
38
+ const StyledText = /*#__PURE__*/_styled(Text, {
39
+ target: "e1kzy2rr5"
40
+ })("margin-left:", _ref4 => {
41
+ let {
42
+ theme
43
+ } = _ref4;
44
+ return theme.space['1'];
45
+ }, ";");
46
+ const MaxWidthText = /*#__PURE__*/_styled(Text, {
47
+ target: "e1kzy2rr4"
48
+ })(process.env.NODE_ENV === "production" ? {
49
+ name: "88bww",
50
+ styles: "max-width:75%"
51
+ } : {
52
+ name: "88bww",
53
+ styles: "max-width:75%",
54
+ toString: _EMOTION_STRINGIFIED_CSS_ERROR__
55
+ });
56
+ const TextAlignRight = /*#__PURE__*/_styled(Text, {
57
+ target: "e1kzy2rr3"
58
+ })(process.env.NODE_ENV === "production" ? {
59
+ name: "2qga7i",
60
+ styles: "text-align:right"
61
+ } : {
62
+ name: "2qga7i",
63
+ styles: "text-align:right",
64
+ toString: _EMOTION_STRINGIFIED_CSS_ERROR__
65
+ });
66
+ const StyledTooltip = /*#__PURE__*/_styled(Tooltip, {
67
+ target: "e1kzy2rr2"
68
+ })(process.env.NODE_ENV === "production" ? {
69
+ name: "uaxjgr",
70
+ styles: "vertical-align:text-top"
71
+ } : {
72
+ name: "uaxjgr",
73
+ styles: "vertical-align:text-top",
74
+ toString: _EMOTION_STRINGIFIED_CSS_ERROR__
75
+ });
76
+ const StyledPriceCell = /*#__PURE__*/_styled(Cell, {
77
+ target: "e1kzy2rr1"
78
+ })(_ref5 => {
79
+ let {
80
+ theme
81
+ } = _ref5;
82
+ return PriceCell(theme);
83
+ }, ";");
84
+ const StyleNoPriceItem = /*#__PURE__*/_styled(Text, {
85
+ target: "e1kzy2rr0"
86
+ })(process.env.NODE_ENV === "production" ? {
87
+ name: "2qga7i",
88
+ styles: "text-align:right"
89
+ } : {
90
+ name: "2qga7i",
91
+ styles: "text-align:right",
92
+ toString: _EMOTION_STRINGIFIED_CSS_ERROR__
93
+ });
94
+ const Item = _ref6 => {
95
+ let {
96
+ discount = 0,
97
+ priceText,
98
+ discountText,
99
+ label,
100
+ tooltipInfo,
101
+ // Shows an icon with tooltip that contains this text
102
+ subLabel = '',
103
+ // Usually used for showing amount that is free
104
+ price: basePrice = 0,
105
+ // Hourly price for one unit
106
+ monthlyPrice = 0,
107
+ // Price per month
108
+ unit: baseUnit,
109
+ // Can be GB, MB, Node, Queries, etc.
110
+ amount: currentAmount = 1,
111
+ // Current number of items
112
+ onAmountChange,
113
+ amountFree = 0,
114
+ // Amount that is free - offered by company
115
+ maxAmount = 0,
116
+ // Max amount - used for kubernetes for example
117
+ longFractionDigits = false,
118
+ // In case price is really long 0.0000076 - up 7 fraction digits
119
+ noIteration = false,
120
+ // if item is not based on time (ex: download, upload, transfer)
121
+ noIterationText,
122
+ noBorder,
123
+ // remove the border bottom of the item
124
+ noPrice,
125
+ // remove the price on right side of the table
126
+ isDefined = true,
127
+ children = null,
128
+ isFirstElement = false,
129
+ isLastElement = false,
130
+ isPrimaryBackground = false,
131
+ productsCallback,
132
+ iteration: receivedIteration,
133
+ // Object from parent that contains time period (hours, days, months)
134
+ shouldBeHidden = false,
135
+ // Hide element from overlay if screen width is small
136
+ hideFromOverlay = false,
137
+ // Hide element from overlay in any case
138
+ textNotDefined,
139
+ // Text to display in case of not defined value
140
+ animated = false,
141
+ // if true, zoomIn animation is triggered
142
+ tabulation,
143
+ // Increase left padding of the item
144
+ labelTextVariant,
145
+ // To change left cell typography variant
146
+ labelTextProminence,
147
+ // To change left cell typography prominence
148
+ notice // To display a gray text below the label
149
+ } = _ref6;
150
+ const {
151
+ locales,
152
+ formatNumber
153
+ } = useEstimateCost();
154
+ let iteration;
155
+ if (noIteration) {
156
+ iteration = {
157
+ ...(receivedIteration ?? {
158
+ value: 0
159
+ }),
160
+ unit: 'hours'
161
+ };
162
+ } else {
163
+ iteration = receivedIteration;
164
+ }
165
+ const price = useMemo(() => {
166
+ if (monthlyPrice > 0 && basePrice === 0) {
167
+ return monthlyPrice / multiplier.months;
168
+ }
169
+ return basePrice;
170
+ }, [basePrice, monthlyPrice]);
171
+ const unit = useMemo(() => {
172
+ if (!baseUnit) {
173
+ return locales['estimate.cost.units.gb.label'];
174
+ }
175
+ return baseUnit;
176
+ }, [baseUnit, locales]);
177
+ const {
178
+ isOverlay
179
+ } = useOverlay();
180
+ const Row = isOverlay ? OverlayRow : 'tr';
181
+ const Cell$1 = isOverlay ? Cell.withComponent('div', {
182
+ target: "e1kzy2rr8"
183
+ }) : Cell;
184
+ const LeftSide = isOverlay ? 'div' : StyledLeftSide;
185
+ const [amount, setAmount] = useState(currentAmount);
186
+ const [isVariant, setIsVariant] = useState(false);
187
+ useEffect(() => setAmount(currentAmount), [setAmount, currentAmount]);
188
+ useEffect(() => onAmountChange?.(amount), [onAmountChange, amount]);
189
+ const itemCallback = useCallback((localAmount, localIsVariant) => {
190
+ setAmount(localAmount);
191
+ setIsVariant(localIsVariant);
192
+ }, [setAmount, setIsVariant]);
193
+ const id = useId();
194
+
195
+ // We remove Item from object list when Iem component unmount to avoid duplicates
196
+ useEffect(() => () => productsCallback?.remove({
197
+ id
198
+ }), [id, productsCallback]);
199
+ useEffect(() => {
200
+ if (!isOverlay) {
201
+ productsCallback?.add({
202
+ id,
203
+ amount,
204
+ price,
205
+ amountFree,
206
+ isVariant,
207
+ maxAmount,
208
+ noIteration,
209
+ longFractionDigits,
210
+ discount
211
+ });
212
+ }
213
+ }, [price, discount, amount, id, productsCallback, maxAmount, noIteration, isVariant, amountFree, isOverlay, longFractionDigits]);
214
+ const computedItemPrice = useMemo(() => calculatePrice({
215
+ price,
216
+ amount,
217
+ amountFree,
218
+ timeUnit: noIteration ? 'hours' : iteration?.unit ?? 'hours',
219
+ timeAmount: noIteration ? 1 : iteration?.value ?? 1,
220
+ discount
221
+ }), [price, amount, amountFree, iteration, noIteration, discount]);
222
+ const computedMaxItemPrice = useMemo(() => calculatePrice({
223
+ price,
224
+ amount: maxAmount,
225
+ amountFree,
226
+ timeUnit: noIteration ? 'hours' : iteration?.unit ?? 'hours',
227
+ timeAmount: noIteration ? 1 : iteration?.value ?? 1,
228
+ discount
229
+ }), [price, maxAmount, amountFree, iteration, noIteration, discount]);
230
+ const formatMaximumFractionDigits = useMemo(() => {
231
+ if (!iteration?.unit) {
232
+ return undefined;
233
+ }
234
+ return longFractionDigits ? maximumFractionDigitsLong[iteration?.unit] : maximumFractionDigits[iteration?.unit];
235
+ }, [iteration?.unit, longFractionDigits]);
236
+ return jsxs(Row, {
237
+ isFirstElement: isFirstElement,
238
+ shouldBeHidden: shouldBeHidden,
239
+ hideFromOverlay: hideFromOverlay,
240
+ children: [jsx(Cell$1, {
241
+ width: !isOverlay ? MAX_CELL_WIDTH : 'inherit',
242
+ hasBorder: !isLastElement && !noBorder && !isOverlay,
243
+ tabulation: tabulation,
244
+ children: jsxs(LeftSide, {
245
+ children: [jsxs(Stack, {
246
+ children: [jsxs(Stack, {
247
+ direction: "row",
248
+ children: [jsx(Text, {
249
+ as: "p",
250
+ variant: labelTextVariant ?? 'body',
251
+ prominence: labelTextProminence ?? 'default',
252
+ children: label
253
+ }), tooltipInfo ? jsx(StyledDiv, {
254
+ children: jsx(StyledTooltip, {
255
+ text: tooltipInfo,
256
+ children: jsx(Icon, {
257
+ name: "help-circle-outline",
258
+ size: 20
259
+ })
260
+ })
261
+ }) : null, subLabel && !isOverlay ? jsx(StyledText, {
262
+ as: "p",
263
+ variant: "body",
264
+ color: "primary",
265
+ italic: true,
266
+ children: subLabel
267
+ }) : null, discount > 0 && discountText ? jsx(StyledBadge, {
268
+ prominence: "strong",
269
+ size: "small",
270
+ sentiment: "warning",
271
+ children: discountText
272
+ }) : null]
273
+ }), notice ? jsx(MaxWidthText, {
274
+ as: "p",
275
+ variant: "caption",
276
+ prominence: "weak",
277
+ children: notice
278
+ }) : null]
279
+ }), jsx(StyledResourceName, {
280
+ isOverlay: isOverlay,
281
+ animated: animated,
282
+ children: isDefined ? Children.map(flattenChildren(children), child => /*#__PURE__*/isValidElement(child) ? /*#__PURE__*/cloneElement(child, {
283
+ itemCallback,
284
+ amount,
285
+ maxAmount,
286
+ unit
287
+ }) : null) : textNotDefined || locales['estimate.cost.notDefined']
288
+ })]
289
+ })
290
+ }), !isOverlay ? jsx(StyledPriceCell, {
291
+ hasBorder: !isLastElement && !noBorder,
292
+ primary: isPrimaryBackground,
293
+ children: !noPrice ? jsxs(Fragment, {
294
+ children: [jsxs(StyleNoPriceItem, {
295
+ as: "p",
296
+ variant: noIterationText ? 'headingSmall' : 'bodyStrong',
297
+ prominence: computedItemPrice === 0 && computedMaxItemPrice === 0 ? 'weak' : 'default',
298
+ color: computedItemPrice === 0 && computedMaxItemPrice === 0 ? 'neutral' : 'primary',
299
+ children: [priceText, !priceText ? formatNumber(computedItemPrice, {
300
+ maximumFractionDigits: formatMaximumFractionDigits
301
+ }) : null, noIterationText ? jsxs(Text, {
302
+ sentiment: "primary",
303
+ as: "span",
304
+ variant: "bodySmall",
305
+ children: ["/", noIterationText]
306
+ }) : null, !priceText && computedMaxItemPrice > 0 ? ` - ${formatNumber(computedMaxItemPrice, {
307
+ maximumFractionDigits: formatMaximumFractionDigits
308
+ })}` : null]
309
+ }), amount - amountFree !== 1 && computedItemPrice > 0 || maxAmount > 0 && computedMaxItemPrice > 0 ? jsxs(TextAlignRight, {
310
+ as: "p",
311
+ variant: "body",
312
+ children: [formatNumber(calculatePrice({
313
+ price,
314
+ amount: 1,
315
+ timeUnit: 'hours',
316
+ timeAmount: 1,
317
+ discount
318
+ }), {
319
+ maximumFractionDigits: longFractionDigits ? maximumFractionDigitsLong.hours : maximumFractionDigits.hours
320
+ }), TIME_RELATED_UNIT.includes(unit) ? locales[`estimate.cost.units.${unit}.label`].toLowerCase() : `/${unit}`, !noIteration ? `/${locales['estimate.cost.units.hours.label'].toLowerCase()}` : null]
321
+ }) : null]
322
+ }) : null
323
+ }) : null]
324
+ });
325
+ };
326
+
327
+ export { Item };
@@ -0,0 +1,15 @@
1
+ import _styled from '@emotion/styled/base';
2
+ import { css } from '@emotion/react';
3
+
4
+ const LineThrough = /*#__PURE__*/_styled('span', {
5
+ shouldForwardProp: prop => !['isActive'].includes(prop),
6
+ target: "e1d1k6i0"
7
+ })(_ref => {
8
+ let {
9
+ isActive,
10
+ theme
11
+ } = _ref;
12
+ return isActive ? /*#__PURE__*/css("text-decoration-line:line-through;text-decoration-color:", theme.colors.warning.border, ";") : null;
13
+ }, ";");
14
+
15
+ export { LineThrough };