@danske/sapphire-react-lab 0.104.0 → 0.105.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.
Files changed (35) hide show
  1. package/README.md +2 -1
  2. package/build/cjs/index.js +729 -234
  3. package/build/cjs/index.js.map +1 -1
  4. package/build/esm/Amount/src/Amount.js +76 -0
  5. package/build/esm/Amount/src/Amount.js.map +1 -0
  6. package/build/esm/Amount/src/useGroupAmount.js +35 -0
  7. package/build/esm/Amount/src/useGroupAmount.js.map +1 -0
  8. package/build/esm/Autocomplete/src/Autocomplete.js +13 -3
  9. package/build/esm/Autocomplete/src/Autocomplete.js.map +1 -1
  10. package/build/esm/Breadcrumbs/src/BreadcrumbItemLink.js +1 -1
  11. package/build/esm/Breadcrumbs/src/BreadcrumbItemLink.js.map +1 -1
  12. package/build/esm/Filtering/src/FilterDropdown.js +8 -3
  13. package/build/esm/Filtering/src/FilterDropdown.js.map +1 -1
  14. package/build/esm/Filtering/src/SearchableSelectFilter.js +2 -1
  15. package/build/esm/Filtering/src/SearchableSelectFilter.js.map +1 -1
  16. package/build/esm/NumberField/src/NumberField.js +53 -21
  17. package/build/esm/NumberField/src/NumberField.js.map +1 -1
  18. package/build/esm/NumberField/src/StepperButton.js +8 -4
  19. package/build/esm/NumberField/src/StepperButton.js.map +1 -1
  20. package/build/esm/NumberField/src/cursorHelpers.js +55 -0
  21. package/build/esm/NumberField/src/cursorHelpers.js.map +1 -0
  22. package/build/esm/NumberField/src/formatHelpers.js +81 -0
  23. package/build/esm/NumberField/src/formatHelpers.js.map +1 -0
  24. package/build/esm/NumberField/src/keyboardHelpers.js +120 -0
  25. package/build/esm/NumberField/src/keyboardHelpers.js.map +1 -0
  26. package/build/esm/NumberField/src/useNumberFieldFormatting.js +94 -0
  27. package/build/esm/NumberField/src/useNumberFieldFormatting.js.map +1 -0
  28. package/build/esm/NumberField/src/useSapphireNumberField.js +1 -1
  29. package/build/esm/NumberField/src/useSapphireNumberField.js.map +1 -1
  30. package/build/esm/TagGroup/src/Tag.js +31 -23
  31. package/build/esm/TagGroup/src/Tag.js.map +1 -1
  32. package/build/esm/index.js +1 -0
  33. package/build/esm/index.js.map +1 -1
  34. package/build/index.d.ts +72 -7
  35. package/package.json +36 -36
@@ -0,0 +1,76 @@
1
+ import React, { useMemo } from 'react';
2
+ import { useThemeCheck, useSapphireStyleProps, Typography } from '@danske/sapphire-react';
3
+ import { useLocale } from '@react-aria/i18n';
4
+ import { useGroupAmount } from './useGroupAmount.js';
5
+ import styles from '@danske/sapphire-css/components/amount/amount.module.css';
6
+
7
+ var __defProp = Object.defineProperty;
8
+ var __defProps = Object.defineProperties;
9
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
10
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
11
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
12
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
13
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
14
+ var __spreadValues = (a, b) => {
15
+ for (var prop in b || (b = {}))
16
+ if (__hasOwnProp.call(b, prop))
17
+ __defNormalProp(a, prop, b[prop]);
18
+ if (__getOwnPropSymbols)
19
+ for (var prop of __getOwnPropSymbols(b)) {
20
+ if (__propIsEnum.call(b, prop))
21
+ __defNormalProp(a, prop, b[prop]);
22
+ }
23
+ return a;
24
+ };
25
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
26
+ var __objRest = (source, exclude) => {
27
+ var target = {};
28
+ for (var prop in source)
29
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
30
+ target[prop] = source[prop];
31
+ if (source != null && __getOwnPropSymbols)
32
+ for (var prop of __getOwnPropSymbols(source)) {
33
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
34
+ target[prop] = source[prop];
35
+ }
36
+ return target;
37
+ };
38
+ const Amount = (_a) => {
39
+ var _b = _a, {
40
+ emphasis = "regular",
41
+ variant,
42
+ formatOptions,
43
+ value,
44
+ size
45
+ } = _b, props = __objRest(_b, [
46
+ "emphasis",
47
+ "variant",
48
+ "formatOptions",
49
+ "value",
50
+ "size"
51
+ ]);
52
+ useThemeCheck();
53
+ const { styleProps, filteredProps } = useSapphireStyleProps(props);
54
+ const { locale } = useLocale();
55
+ const formatter = useMemo(() => new Intl.NumberFormat(locale, __spreadValues({
56
+ style: (formatOptions == null ? void 0 : formatOptions.currency) ? "currency" : void 0,
57
+ signDisplay: (formatOptions == null ? void 0 : formatOptions.signDisplay) || String(value).startsWith("+") ? "always" : "auto",
58
+ minimumFractionDigits: 2
59
+ }, formatOptions)), [locale, formatOptions, value]);
60
+ const { formattedValue, groupedParts } = useGroupAmount(value, formatter);
61
+ return /* @__PURE__ */ React.createElement("span", __spreadProps(__spreadValues({
62
+ style: styleProps.style,
63
+ className: styles["sapphire-amount"]
64
+ }, filteredProps), {
65
+ "aria-label": formattedValue
66
+ }), groupedParts.map((part, index) => /* @__PURE__ */ React.createElement(Typography.Body, {
67
+ elementType: "span",
68
+ key: index,
69
+ color: variant === "positive" ? "positive" : "primary",
70
+ isSemibold: emphasis === "primary" ? true : false,
71
+ size
72
+ }, part.value)));
73
+ };
74
+
75
+ export { Amount };
76
+ //# sourceMappingURL=Amount.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Amount.js","sources":["../../../../src/Amount/src/Amount.tsx"],"sourcesContent":["import { useMemo } from 'react';\nimport {\n useThemeCheck,\n SapphireStyleProps,\n GlobalDomAttributes,\n Typography,\n TypographyBodyProps,\n useSapphireStyleProps,\n} from '@danske/sapphire-react';\nimport React from 'react';\nimport { useLocale } from '@react-aria/i18n';\nimport { useGroupAmount } from './useGroupAmount';\nimport styles from '@danske/sapphire-css/components/amount/amount.module.css';\n\n/**\n * Format options for currency amounts.\n * The style is always 'currency', so only currency-related options are exposed.\n */\nexport type CurrencyFormatOptions = Pick<\n Intl.NumberFormatOptions,\n | 'currency'\n | 'currencyDisplay'\n | 'currencySign'\n | 'signDisplay'\n | 'minimumFractionDigits'\n | 'maximumFractionDigits'\n | 'minimumSignificantDigits'\n | 'maximumSignificantDigits'\n | 'useGrouping'\n | 'notation'\n>;\n\nexport type AmountProps = {\n /**\n * When displaying amounts, readability and visual hierarchy are key. Use medium weight for primary emphasis to highlight amounts or regular weight for secondary emphasis.\n *\n * @default 'regular'\n */\n emphasis?: 'primary' | 'regular';\n /**\n * The variant of the Amount component. `positive` shows a green color, and should be used for amounts greater than zero.\n *\n * @default 'neutal'\n */\n variant?: 'neutal' | 'positive';\n /**\n * The amount value to be formatted and displayed.\n *\n * If displaying the sign is a requirement, ensure the value is a string that starts with '+' or '-'.\n * Alternatively, you can use the `signDisplay` option in `formatOptions` to control the display of the sign for numeric values.\n */\n value: string | number;\n /** Currency formatting options */\n formatOptions?: CurrencyFormatOptions;\n} & Pick<TypographyBodyProps, 'size'> &\n SapphireStyleProps &\n GlobalDomAttributes;\n\nexport const Amount = ({\n emphasis = 'regular',\n variant,\n formatOptions,\n value,\n size,\n ...props\n}: AmountProps): JSX.Element => {\n useThemeCheck();\n const { styleProps, filteredProps } = useSapphireStyleProps(props);\n const { locale } = useLocale();\n\n const formatter = useMemo(\n () =>\n new Intl.NumberFormat(locale, {\n style: formatOptions?.currency ? 'currency' : undefined,\n /**\n * Always show the sign if the value starts with '+' or '-'.\n */\n signDisplay:\n formatOptions?.signDisplay || String(value).startsWith('+')\n ? 'always'\n : 'auto',\n minimumFractionDigits: 2,\n ...formatOptions,\n }),\n [locale, formatOptions, value]\n );\n\n const { formattedValue, groupedParts } = useGroupAmount(value, formatter);\n\n return (\n <span\n style={styleProps.style}\n className={styles['sapphire-amount']}\n {...filteredProps}\n aria-label={formattedValue}\n >\n {groupedParts.map((part, index) => (\n <Typography.Body\n elementType=\"span\"\n key={index}\n color={variant === 'positive' ? 'positive' : 'primary'}\n isSemibold={emphasis === 'primary' ? true : false}\n size={size}\n >\n {part.value}\n </Typography.Body>\n ))}\n </span>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0Da,MAAA,MAAA,GAAS,CAAC,EAOS,KAAA;AAPT,EACrB,IAAA,EAAA,GAAA,EAAA,EAAA;AAAA,IAAW,QAAA,GAAA,SAAA;AAAA,IACX,OAAA;AAAA,IACA,aAAA;AAAA,IACA,KAAA;AAAA,IACA,IAAA;AAAA,GALqB,GAAA,EAAA,EAMlB,kBANkB,EAMlB,EAAA;AAAA,IALH,UAAA;AAAA,IACA,SAAA;AAAA,IACA,eAAA;AAAA,IACA,OAAA;AAAA,IACA,MAAA;AAAA,GAAA,CAAA,CAAA;AAGA,EAAA,aAAA,EAAA,CAAA;AACA,EAAM,MAAA,EAAE,UAAY,EAAA,aAAA,EAAA,GAAkB,qBAAsB,CAAA,KAAA,CAAA,CAAA;AAC5D,EAAA,MAAM,EAAE,MAAW,EAAA,GAAA,SAAA,EAAA,CAAA;AAEnB,EAAA,MAAM,YAAY,OAChB,CAAA,MACE,IAAI,IAAA,CAAK,aAAa,MAAQ,EAAA,cAAA,CAAA;AAAA,IAC5B,KAAA,EAAO,CAAe,aAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,aAAA,CAAA,QAAA,IAAW,UAAa,GAAA,KAAA,CAAA;AAAA,IAI9C,aACE,CAAe,aAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,aAAA,CAAA,WAAA,KAAe,OAAO,KAAO,CAAA,CAAA,UAAA,CAAW,OACnD,QACA,GAAA,MAAA;AAAA,IACN,qBAAuB,EAAA,CAAA;AAAA,GACpB,EAAA,aAAA,CAAA,CAAA,EAEP,CAAC,MAAA,EAAQ,aAAe,EAAA,KAAA,CAAA,CAAA,CAAA;AAG1B,EAAA,MAAM,EAAE,cAAA,EAAgB,YAAiB,EAAA,GAAA,cAAA,CAAe,KAAO,EAAA,SAAA,CAAA,CAAA;AAE/D,EAAA,2CACG,MAAD,EAAA,aAAA,CAAA,cAAA,CAAA;AAAA,IACE,OAAO,UAAW,CAAA,KAAA;AAAA,IAClB,WAAW,MAAO,CAAA,iBAAA,CAAA;AAAA,GAAA,EACd,aAHN,CAAA,EAAA;AAAA,IAIE,YAAY,EAAA,cAAA;AAAA,GAAA,CAAA,EAEX,aAAa,GAAI,CAAA,CAAC,MAAM,KACvB,qBAAA,KAAA,CAAA,aAAA,CAAC,WAAW,IAAZ,EAAA;AAAA,IACE,WAAY,EAAA,MAAA;AAAA,IACZ,GAAK,EAAA,KAAA;AAAA,IACL,KAAA,EAAO,OAAY,KAAA,UAAA,GAAa,UAAa,GAAA,SAAA;AAAA,IAC7C,UAAA,EAAY,QAAa,KAAA,SAAA,GAAY,IAAO,GAAA,KAAA;AAAA,IAC5C,IAAA;AAAA,GAAA,EAEC,IAAK,CAAA,KAAA,CAAA,CAAA,CAAA,CAAA;AAAA;;;;"}
@@ -0,0 +1,35 @@
1
+ import { useMemo } from 'react';
2
+
3
+ const useGroupAmount = (value, formatter) => {
4
+ const numberValue = useMemo(() => {
5
+ const parsed = Number(value);
6
+ return isNaN(parsed) ? 0 : parsed;
7
+ }, [value]);
8
+ const groupedParts = useMemo(() => {
9
+ const parts = formatter.formatToParts(numberValue);
10
+ const result = [];
11
+ let currentNumber = "";
12
+ parts.forEach((part) => {
13
+ if (part.type === "plusSign" || part.type === "minusSign") {
14
+ result.push({ type: "sign", value: part.value });
15
+ } else if (part.type === "currency") {
16
+ if (currentNumber) {
17
+ result.push({ type: "number", value: currentNumber });
18
+ currentNumber = "";
19
+ }
20
+ result.push({ type: "currency", value: part.value });
21
+ } else if (part.type !== "literal") {
22
+ currentNumber += part.value;
23
+ }
24
+ });
25
+ if (currentNumber) {
26
+ result.push({ type: "number", value: currentNumber });
27
+ }
28
+ return result;
29
+ }, [numberValue, formatter]);
30
+ const formattedValue = useMemo(() => groupedParts.map((part) => part.value).join(""), [groupedParts]);
31
+ return { formattedValue, groupedParts };
32
+ };
33
+
34
+ export { useGroupAmount };
35
+ //# sourceMappingURL=useGroupAmount.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useGroupAmount.js","sources":["../../../../src/Amount/src/useGroupAmount.ts"],"sourcesContent":["import { useMemo } from 'react';\n\nexport interface GroupedPart {\n type: 'sign' | 'number' | 'currency';\n value: string;\n}\n\n/**\n * Process the value that is being provided and format it using the provided formatter.\n * It returns both the formatted value as a string and the grouped parts for further processing.\n * It's useful for keeping track of diffrent parts of the formatted amount and where currency symbols are located.\n *\n * Example: value = \"+30000\", formatter for DKK currency\n * formattedValue = \"+DKK 30,000.00\"\n * groupedParts = [\n * { type: 'sign', value: '+' },\n * { type: 'currency', value: 'DKK' },\n * { type: 'number', value: '30,000.00' }\n * ]\n */\nexport const useGroupAmount = (\n value: string | number,\n formatter: Intl.NumberFormat\n) => {\n const numberValue = useMemo(() => {\n const parsed = Number(value);\n return isNaN(parsed) ? 0 : parsed;\n }, [value]);\n\n const groupedParts = useMemo(() => {\n const parts = formatter.formatToParts(numberValue);\n const result: GroupedPart[] = [];\n let currentNumber = '';\n\n parts.forEach((part) => {\n if (part.type === 'plusSign' || part.type === 'minusSign') {\n result.push({ type: 'sign', value: part.value });\n } else if (part.type === 'currency') {\n if (currentNumber) {\n result.push({ type: 'number', value: currentNumber });\n currentNumber = '';\n }\n result.push({ type: 'currency', value: part.value });\n } else if (part.type !== 'literal') {\n currentNumber += part.value;\n }\n });\n\n if (currentNumber) {\n result.push({ type: 'number', value: currentNumber });\n }\n\n return result;\n }, [numberValue, formatter]);\n\n const formattedValue = useMemo(\n () => groupedParts.map((part) => part.value).join(''),\n [groupedParts]\n );\n\n return { formattedValue, groupedParts };\n};\n"],"names":[],"mappings":";;AAoBa,MAAA,cAAA,GAAiB,CAC5B,KAAA,EACA,SACG,KAAA;AACH,EAAM,MAAA,WAAA,GAAc,QAAQ,MAAM;AAChC,IAAA,MAAM,SAAS,MAAO,CAAA,KAAA,CAAA,CAAA;AACtB,IAAO,OAAA,KAAA,CAAM,UAAU,CAAI,GAAA,MAAA,CAAA;AAAA,GAAA,EAC1B,CAAC,KAAA,CAAA,CAAA,CAAA;AAEJ,EAAM,MAAA,YAAA,GAAe,QAAQ,MAAM;AACjC,IAAM,MAAA,KAAA,GAAQ,UAAU,aAAc,CAAA,WAAA,CAAA,CAAA;AACtC,IAAA,MAAM,MAAwB,GAAA,EAAA,CAAA;AAC9B,IAAA,IAAI,aAAgB,GAAA,EAAA,CAAA;AAEpB,IAAM,KAAA,CAAA,OAAA,CAAQ,CAAC,IAAS,KAAA;AACtB,MAAA,IAAI,IAAK,CAAA,IAAA,KAAS,UAAc,IAAA,IAAA,CAAK,SAAS,WAAa,EAAA;AACzD,QAAA,MAAA,CAAO,IAAK,CAAA,EAAE,IAAM,EAAA,MAAA,EAAQ,OAAO,IAAK,CAAA,KAAA,EAAA,CAAA,CAAA;AAAA,OAC/B,MAAA,IAAA,IAAA,CAAK,SAAS,UAAY,EAAA;AACnC,QAAA,IAAI,aAAe,EAAA;AACjB,UAAA,MAAA,CAAO,IAAK,CAAA,EAAE,IAAM,EAAA,QAAA,EAAU,KAAO,EAAA,aAAA,EAAA,CAAA,CAAA;AACrC,UAAgB,aAAA,GAAA,EAAA,CAAA;AAAA,SAAA;AAElB,QAAA,MAAA,CAAO,IAAK,CAAA,EAAE,IAAM,EAAA,UAAA,EAAY,OAAO,IAAK,CAAA,KAAA,EAAA,CAAA,CAAA;AAAA,OACnC,MAAA,IAAA,IAAA,CAAK,SAAS,SAAW,EAAA;AAClC,QAAA,aAAA,IAAiB,IAAK,CAAA,KAAA,CAAA;AAAA,OAAA;AAAA,KAAA,CAAA,CAAA;AAI1B,IAAA,IAAI,aAAe,EAAA;AACjB,MAAA,MAAA,CAAO,IAAK,CAAA,EAAE,IAAM,EAAA,QAAA,EAAU,KAAO,EAAA,aAAA,EAAA,CAAA,CAAA;AAAA,KAAA;AAGvC,IAAO,OAAA,MAAA,CAAA;AAAA,GAAA,EACN,CAAC,WAAa,EAAA,SAAA,CAAA,CAAA,CAAA;AAEjB,EAAM,MAAA,cAAA,GAAiB,OACrB,CAAA,MAAM,YAAa,CAAA,GAAA,CAAI,CAAC,IAAA,KAAS,IAAK,CAAA,KAAA,CAAA,CAAO,IAAK,CAAA,EAAA,CAAA,EAClD,CAAC,YAAA,CAAA,CAAA,CAAA;AAGH,EAAA,OAAO,EAAE,cAAgB,EAAA,YAAA,EAAA,CAAA;AAAA;;;;"}
@@ -46,13 +46,17 @@ function Autocomplete(props) {
46
46
  renderInput,
47
47
  loadingState,
48
48
  loadingSkeletonRowsCount,
49
- listboxAriaLabel
49
+ listboxAriaLabel,
50
+ onSuggestionSelected,
51
+ onSelectionChange
50
52
  } = _a, otherProps = __objRest(_a, [
51
53
  "inputValue",
52
54
  "renderInput",
53
55
  "loadingState",
54
56
  "loadingSkeletonRowsCount",
55
- "listboxAriaLabel"
57
+ "listboxAriaLabel",
58
+ "onSuggestionSelected",
59
+ "onSelectionChange"
56
60
  ]);
57
61
  const {
58
62
  styleProps: { style, className }
@@ -65,7 +69,13 @@ function Autocomplete(props) {
65
69
  inputValue,
66
70
  allowsEmptyCollection: loadingState === "loading",
67
71
  allowsCustomValue: true,
68
- shouldCloseOnBlur: true
72
+ shouldCloseOnBlur: true,
73
+ onSelectionChange: (key) => {
74
+ if (key !== null) {
75
+ onSelectionChange == null ? void 0 : onSelectionChange(key);
76
+ onSuggestionSelected == null ? void 0 : onSuggestionSelected(key);
77
+ }
78
+ }
69
79
  }));
70
80
  const { inputProps, listBoxProps } = useComboBox(__spreadProps(__spreadValues({}, props), {
71
81
  "aria-label": listboxAriaLabel || formatMessage("listbox-suggestions"),
@@ -1 +1 @@
1
- {"version":3,"file":"Autocomplete.js","sources":["../../../../src/Autocomplete/src/Autocomplete.tsx"],"sourcesContent":["import React, { ReactElement, useRef } from 'react';\nimport {\n ListBoxProps,\n useThemeCheck,\n useSapphireStyleProps,\n SapphireStyleProps,\n ListBoxPopover,\n useComboBoxState,\n GlobalDomAttributes,\n} from '@danske/sapphire-react';\nimport { useComboBox } from '@react-aria/combobox';\nimport { useMessageFormatter } from '@react-aria/i18n';\nimport intlMessages from '../i18n';\nimport { useFocusableRef } from '@react-spectrum/utils';\nimport type { ComboBoxProps } from '@react-types/combobox';\nimport { filterDOMProps } from '@react-aria/utils';\n\nexport type AutocompleteProps<T extends object> = GlobalDomAttributes &\n SapphireStyleProps &\n Pick<\n ComboBoxProps<T>,\n | 'items'\n | 'children'\n | 'inputValue'\n | 'defaultInputValue'\n | 'onInputChange'\n | 'onSelectionChange'\n | 'isDisabled'\n > &\n Pick<ListBoxProps<T>, 'loadingState' | 'loadingSkeletonRowsCount'> & {\n /**\n * Render function for the input element.\n * Receives props that should be spread onto the input component.\n */\n renderInput: (inputProps: any) => ReactElement;\n\n /**\n * Accessible label for the suggestions listbox.\n */\n listboxAriaLabel?: string;\n\n /**\n * Controlled selected value.\n */\n value?: React.Key | null;\n\n /**\n * Decide what items to display in the dropdown menu.\n * @default 'String.includes'\n */\n defaultFilter?: (textValue: string, inputValue: string) => boolean;\n };\n\nexport function Autocomplete<T extends object>(\n props: AutocompleteProps<T>\n): ReactElement {\n useThemeCheck();\n const formatMessage = useMessageFormatter(intlMessages);\n\n const {\n inputValue,\n renderInput,\n loadingState,\n loadingSkeletonRowsCount,\n listboxAriaLabel,\n ...otherProps\n } = props;\n\n const {\n styleProps: { style, className },\n } = useSapphireStyleProps(props);\n\n const inputRef = useRef<HTMLInputElement>(null);\n const listBoxRef = useFocusableRef<HTMLUListElement>(null);\n const popoverRef = useRef<HTMLDivElement>(null);\n const triggerRef = useFocusableRef<HTMLDivElement>(null);\n\n const state = useComboBoxState({\n ...props,\n inputValue,\n allowsEmptyCollection: loadingState === 'loading',\n allowsCustomValue: true,\n shouldCloseOnBlur: true,\n });\n\n const { inputProps, listBoxProps } = useComboBox(\n {\n ...props,\n 'aria-label': listboxAriaLabel || formatMessage('listbox-suggestions'),\n inputRef,\n listBoxRef,\n popoverRef,\n },\n state\n );\n\n const inputElement = renderInput({\n ...inputProps,\n isDisabled: props.isDisabled,\n inputRef,\n 'aria-haspopup': 'listbox',\n 'aria-expanded': state.isOpen,\n onChange: (value: string) => {\n inputProps.onChange?.({\n target: { value },\n currentTarget: { value },\n } as React.ChangeEvent<HTMLInputElement>);\n },\n });\n\n return (\n <div\n ref={triggerRef}\n {...filterDOMProps(otherProps, { global: true })}\n style={{ display: 'inline-flex', ...style }}\n className={className}\n >\n {inputElement}\n {state.isOpen && (\n <ListBoxPopover<T>\n state={state}\n triggerRef={triggerRef}\n popoverRef={popoverRef}\n listBoxRef={listBoxRef}\n listBoxProps={listBoxProps}\n loadingState={loadingState}\n loadingSkeletonRowsCount={loadingSkeletonRowsCount}\n selectWidth={triggerRef.current?.offsetWidth}\n disableSelectedStyles\n isNonModal\n >\n {props.children || []}\n </ListBoxPopover>\n )}\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Autocomplete.js","sources":["../../../../src/Autocomplete/src/Autocomplete.tsx"],"sourcesContent":["import React, { Key, ReactElement, useRef } from 'react';\nimport {\n ListBoxProps,\n useThemeCheck,\n useSapphireStyleProps,\n SapphireStyleProps,\n ListBoxPopover,\n useComboBoxState,\n GlobalDomAttributes,\n} from '@danske/sapphire-react';\nimport { useComboBox } from '@react-aria/combobox';\nimport { useMessageFormatter } from '@react-aria/i18n';\nimport intlMessages from '../i18n';\nimport { useFocusableRef } from '@react-spectrum/utils';\nimport type { ComboBoxProps } from '@react-types/combobox';\nimport { filterDOMProps } from '@react-aria/utils';\n\nexport type AutocompleteProps<T extends object> = GlobalDomAttributes &\n SapphireStyleProps &\n Pick<\n ComboBoxProps<T>,\n | 'items'\n | 'children'\n | 'inputValue'\n | 'defaultInputValue'\n | 'onInputChange'\n | 'isDisabled'\n > &\n Pick<ListBoxProps<T>, 'loadingState' | 'loadingSkeletonRowsCount'> & {\n /**\n * This prop is badly named. It is NOT related to a selection state being\n * changed since there is no selection state in this component.\n *\n * This callback simply notifies you when the user filled in the text field\n * by selecting an option from the autocomplete dropdown. Similar to an\n * onClick.\n *\n * @deprecated\n * Use `onSuggestionSelected` instead.\n */\n onSelectionChange?: Pick<\n ComboBoxProps<T>,\n 'onSelectionChange'\n >['onSelectionChange'];\n\n /*\n * This callback simply notifies you when the user filled in the text field\n * by selecting an option from the autocomplete dropdown. Similar to an\n * onClick.\n */\n onSuggestionSelected?: (key: Key) => void;\n /**\n * Render function for the input element.\n * Receives props that should be spread onto the input component.\n */\n renderInput: (inputProps: any) => ReactElement;\n\n /**\n * Accessible label for the suggestions listbox.\n */\n listboxAriaLabel?: string;\n\n /**\n * Controlled selected value.\n */\n value?: React.Key | null;\n\n /**\n * Decide what items to display in the dropdown menu.\n * @default 'String.includes'\n */\n defaultFilter?: (textValue: string, inputValue: string) => boolean;\n };\n\nexport function Autocomplete<T extends object>(\n props: AutocompleteProps<T>\n): ReactElement {\n useThemeCheck();\n const formatMessage = useMessageFormatter(intlMessages);\n\n const {\n inputValue,\n renderInput,\n loadingState,\n loadingSkeletonRowsCount,\n listboxAriaLabel,\n onSuggestionSelected,\n onSelectionChange,\n ...otherProps\n } = props;\n\n const {\n styleProps: { style, className },\n } = useSapphireStyleProps(props);\n\n const inputRef = useRef<HTMLInputElement>(null);\n const listBoxRef = useFocusableRef<HTMLUListElement>(null);\n const popoverRef = useRef<HTMLDivElement>(null);\n const triggerRef = useFocusableRef<HTMLDivElement>(null);\n\n const state = useComboBoxState({\n ...props,\n inputValue,\n allowsEmptyCollection: loadingState === 'loading',\n allowsCustomValue: true,\n shouldCloseOnBlur: true,\n onSelectionChange: (key) => {\n if (key !== null) {\n onSelectionChange?.(key);\n onSuggestionSelected?.(key);\n }\n },\n });\n\n const { inputProps, listBoxProps } = useComboBox(\n {\n ...props,\n 'aria-label': listboxAriaLabel || formatMessage('listbox-suggestions'),\n inputRef,\n listBoxRef,\n popoverRef,\n },\n state\n );\n\n const inputElement = renderInput({\n ...inputProps,\n isDisabled: props.isDisabled,\n inputRef,\n 'aria-haspopup': 'listbox',\n 'aria-expanded': state.isOpen,\n onChange: (value: string) => {\n inputProps.onChange?.({\n target: { value },\n currentTarget: { value },\n } as React.ChangeEvent<HTMLInputElement>);\n },\n });\n\n return (\n <div\n ref={triggerRef}\n {...filterDOMProps(otherProps, { global: true })}\n style={{ display: 'inline-flex', ...style }}\n className={className}\n >\n {inputElement}\n {state.isOpen && (\n <ListBoxPopover<T>\n state={state}\n triggerRef={triggerRef}\n popoverRef={popoverRef}\n listBoxRef={listBoxRef}\n listBoxProps={listBoxProps}\n loadingState={loadingState}\n loadingSkeletonRowsCount={loadingSkeletonRowsCount}\n selectWidth={triggerRef.current?.offsetWidth}\n disableSelectedStyles\n isNonModal\n >\n {props.children || []}\n </ListBoxPopover>\n )}\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -40,7 +40,7 @@ const BreadcrumbItemLink = forwardRef(function BreadcrumbItemLink2(_a, ref) {
40
40
  const { styleProps: sapphireStyleProps } = useSapphireStyleProps(props);
41
41
  const _a2 = sapphireStyleProps, { style, className } = _a2, styleProps = __objRest(_a2, ["style", "className"]);
42
42
  const { size } = useContext(BreadcrumbsContext);
43
- if (!props.href) {
43
+ if (!props.href && !props.UNSAFE_onClick) {
44
44
  return /* @__PURE__ */ React.createElement(BreadcrumbItemStatic, __spreadProps(__spreadValues({}, props), {
45
45
  size
46
46
  }), children);
@@ -1 +1 @@
1
- {"version":3,"file":"BreadcrumbItemLink.js","sources":["../../../../src/Breadcrumbs/src/BreadcrumbItemLink.tsx"],"sourcesContent":["import React, { useContext, forwardRef } from 'react';\nimport {\n Button,\n ButtonProps,\n SapphireStyleProps,\n useSapphireStyleProps,\n useThemeCheck,\n GlobalDomAttributes,\n} from '@danske/sapphire-react';\nimport { FocusableRef } from '@react-types/shared';\nimport { BreadcrumbsContext } from './Breadcrumbs';\nimport { BreadcrumbItemStatic } from './BreadcrumbItemStatic';\n\nexport type BreadcrumbItemLinkProps = Pick<\n ButtonProps<'a'>,\n | 'children'\n | 'href'\n | 'hrefLang'\n | 'target'\n | 'rel'\n | 'isDisabled'\n | 'icon'\n // TODO when moving to \"core\", use types under `types.ts` instead of plain strings\n | 'aria-label'\n | 'aria-labelledby'\n | 'aria-describedby'\n | 'aria-details'\n | 'UNSAFE_onClick'\n> &\n SapphireStyleProps &\n GlobalDomAttributes;\n\nexport const BreadcrumbItemLink = forwardRef(function BreadcrumbItemLink(\n { children, ...props }: BreadcrumbItemLinkProps,\n ref: FocusableRef<HTMLAnchorElement>\n): JSX.Element {\n useThemeCheck();\n const { styleProps: sapphireStyleProps } = useSapphireStyleProps(props);\n const { style, className, ...styleProps } = sapphireStyleProps;\n const { size } = useContext(BreadcrumbsContext);\n\n if (!props.href) {\n return (\n <BreadcrumbItemStatic {...props} size={size}>\n {children}\n </BreadcrumbItemStatic>\n );\n }\n\n return (\n <Button\n {...props}\n {...styleProps}\n UNSAFE_className={className}\n UNSAFE_style={{ ...style }}\n ref={ref}\n size={size}\n variant=\"tertiary\"\n isDisabled={props.isDisabled}\n >\n {children}\n </Button>\n );\n});\n\nBreadcrumbItemLink.displayName = 'BreadcrumbItemLink';\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCO,MAAM,kBAAqB,GAAA,UAAA,CAAW,SAC3C,mBAAA,CAAA,EAAA,EACA,GACa,EAAA;AAFb,EAAA,IAAA,EAAA,GAAA,EAAA,EAAE,EAAF,QAAA,EAAA,GAAA,EAAA,EAAe,KAAf,GAAA,SAAA,CAAA,EAAA,EAAe,CAAb,UAAA,CAAA,CAAA,CAAA;AAGF,EAAA,aAAA,EAAA,CAAA;AACA,EAAM,MAAA,EAAE,UAAY,EAAA,kBAAA,EAAA,GAAuB,qBAAsB,CAAA,KAAA,CAAA,CAAA;AACjE,EAAA,MAA4C,0BAApC,EAAO,KAAA,EAAA,SAAA,EAAA,GAA6B,KAAf,UAAe,GAAA,SAAA,CAAA,GAAA,EAAf,CAArB,OAAO,EAAA,WAAA,CAAA,CAAA,CAAA;AACf,EAAM,MAAA,EAAE,SAAS,UAAW,CAAA,kBAAA,CAAA,CAAA;AAE5B,EAAI,IAAA,CAAC,MAAM,IAAM,EAAA;AACf,IACE,uBAAA,KAAA,CAAA,aAAA,CAAC,oBAAD,EAAA,aAAA,CAAA,cAAA,CAAA,EAAA,EAA0B,KAA1B,CAAA,EAAA;AAAA,MAAiC,IAAA;AAAA,KAC9B,CAAA,EAAA,QAAA,CAAA,CAAA;AAAA,GAAA;AAKP,EAAA,uBACG,KAAA,CAAA,aAAA,CAAA,MAAA,EAAD,aACM,CAAA,cAAA,CAAA,cAAA,CAAA,EAAA,EAAA,KAAA,CAAA,EACA,UAFN,CAAA,EAAA;AAAA,IAGE,gBAAkB,EAAA,SAAA;AAAA,IAClB,cAAc,cAAK,CAAA,EAAA,EAAA,KAAA,CAAA;AAAA,IACnB,GAAA;AAAA,IACA,IAAA;AAAA,IACA,OAAQ,EAAA,UAAA;AAAA,IACR,YAAY,KAAM,CAAA,UAAA;AAAA,GAEjB,CAAA,EAAA,QAAA,CAAA,CAAA;AAAA,CAAA,EAAA;AAKP,kBAAA,CAAmB,WAAc,GAAA,oBAAA;;;;"}
1
+ {"version":3,"file":"BreadcrumbItemLink.js","sources":["../../../../src/Breadcrumbs/src/BreadcrumbItemLink.tsx"],"sourcesContent":["import React, { useContext, forwardRef } from 'react';\nimport {\n Button,\n ButtonProps,\n SapphireStyleProps,\n useSapphireStyleProps,\n useThemeCheck,\n GlobalDomAttributes,\n} from '@danske/sapphire-react';\nimport { FocusableRef } from '@react-types/shared';\nimport { BreadcrumbsContext } from './Breadcrumbs';\nimport { BreadcrumbItemStatic } from './BreadcrumbItemStatic';\n\nexport type BreadcrumbItemLinkProps = Pick<\n ButtonProps<'a'>,\n | 'children'\n | 'href'\n | 'hrefLang'\n | 'target'\n | 'rel'\n | 'isDisabled'\n | 'icon'\n // TODO when moving to \"core\", use types under `types.ts` instead of plain strings\n | 'aria-label'\n | 'aria-labelledby'\n | 'aria-describedby'\n | 'aria-details'\n | 'UNSAFE_onClick'\n> &\n SapphireStyleProps &\n GlobalDomAttributes;\n\nexport const BreadcrumbItemLink = forwardRef(function BreadcrumbItemLink(\n { children, ...props }: BreadcrumbItemLinkProps,\n ref: FocusableRef<HTMLAnchorElement>\n): JSX.Element {\n useThemeCheck();\n const { styleProps: sapphireStyleProps } = useSapphireStyleProps(props);\n const { style, className, ...styleProps } = sapphireStyleProps;\n const { size } = useContext(BreadcrumbsContext);\n\n if (!props.href && !props.UNSAFE_onClick) {\n return (\n <BreadcrumbItemStatic {...props} size={size}>\n {children}\n </BreadcrumbItemStatic>\n );\n }\n\n return (\n <Button\n {...props}\n {...styleProps}\n UNSAFE_className={className}\n UNSAFE_style={{ ...style }}\n ref={ref}\n size={size}\n variant=\"tertiary\"\n isDisabled={props.isDisabled}\n >\n {children}\n </Button>\n );\n});\n\nBreadcrumbItemLink.displayName = 'BreadcrumbItemLink';\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCO,MAAM,kBAAqB,GAAA,UAAA,CAAW,SAC3C,mBAAA,CAAA,EAAA,EACA,GACa,EAAA;AAFb,EAAA,IAAA,EAAA,GAAA,EAAA,EAAE,EAAF,QAAA,EAAA,GAAA,EAAA,EAAe,KAAf,GAAA,SAAA,CAAA,EAAA,EAAe,CAAb,UAAA,CAAA,CAAA,CAAA;AAGF,EAAA,aAAA,EAAA,CAAA;AACA,EAAM,MAAA,EAAE,UAAY,EAAA,kBAAA,EAAA,GAAuB,qBAAsB,CAAA,KAAA,CAAA,CAAA;AACjE,EAAA,MAA4C,0BAApC,EAAO,KAAA,EAAA,SAAA,EAAA,GAA6B,KAAf,UAAe,GAAA,SAAA,CAAA,GAAA,EAAf,CAArB,OAAO,EAAA,WAAA,CAAA,CAAA,CAAA;AACf,EAAM,MAAA,EAAE,SAAS,UAAW,CAAA,kBAAA,CAAA,CAAA;AAE5B,EAAA,IAAI,CAAC,KAAA,CAAM,IAAQ,IAAA,CAAC,MAAM,cAAgB,EAAA;AACxC,IACE,uBAAA,KAAA,CAAA,aAAA,CAAC,oBAAD,EAAA,aAAA,CAAA,cAAA,CAAA,EAAA,EAA0B,KAA1B,CAAA,EAAA;AAAA,MAAiC,IAAA;AAAA,KAC9B,CAAA,EAAA,QAAA,CAAA,CAAA;AAAA,GAAA;AAKP,EAAA,uBACG,KAAA,CAAA,aAAA,CAAA,MAAA,EAAD,aACM,CAAA,cAAA,CAAA,cAAA,CAAA,EAAA,EAAA,KAAA,CAAA,EACA,UAFN,CAAA,EAAA;AAAA,IAGE,gBAAkB,EAAA,SAAA;AAAA,IAClB,cAAc,cAAK,CAAA,EAAA,EAAA,KAAA,CAAA;AAAA,IACnB,GAAA;AAAA,IACA,IAAA;AAAA,IACA,OAAQ,EAAA,UAAA;AAAA,IACR,YAAY,KAAM,CAAA,UAAA;AAAA,GAEjB,CAAA,EAAA,QAAA,CAAA,CAAA;AAAA,CAAA,EAAA;AAKP,kBAAA,CAAmB,WAAc,GAAA,oBAAA;;;;"}
@@ -1,8 +1,9 @@
1
1
  import React, { useRef } from 'react';
2
+ import clsx from 'clsx';
2
3
  import { VisuallyHidden } from '@react-aria/visually-hidden';
3
4
  import { useEffectEvent, filterDOMProps } from '@react-aria/utils';
4
5
  import { useControlledState } from '@react-stately/utils';
5
- import { PopoverTrigger, ButtonGroup, Button, ToggleButton } from '@danske/sapphire-react';
6
+ import { useSapphireStyleProps, PopoverTrigger, ButtonGroup, Button, ToggleButton } from '@danske/sapphire-react';
6
7
  import { ChevronUp, ChevronDown } from '@danske/sapphire-icons/react';
7
8
  import styles from '@danske/sapphire-css/components/filterDropdown/filterDropdown.module.css';
8
9
 
@@ -48,6 +49,7 @@ function FilterDropdown(_a) {
48
49
  isOpen: isOpenProp,
49
50
  applyButtonLabel = "Apply",
50
51
  clearButtonLabel = "Clear",
52
+ hideClearButton = false,
51
53
  defaultOpen = false,
52
54
  hasApplyButton = false,
53
55
  noMaxWidth,
@@ -65,6 +67,7 @@ function FilterDropdown(_a) {
65
67
  "isOpen",
66
68
  "applyButtonLabel",
67
69
  "clearButtonLabel",
70
+ "hideClearButton",
68
71
  "defaultOpen",
69
72
  "hasApplyButton",
70
73
  "noMaxWidth",
@@ -74,6 +77,7 @@ function FilterDropdown(_a) {
74
77
  "buttonSize"
75
78
  ]);
76
79
  const triggerRef = useRef(null);
80
+ const { styleProps } = useSapphireStyleProps(props);
77
81
  const [isOpen, setIsOpen] = useControlledState(isOpenProp, defaultOpen, useEffectEvent(onOpenChange));
78
82
  const hasValue = value != null && value !== "";
79
83
  const close = () => setIsOpen(false);
@@ -99,14 +103,15 @@ function FilterDropdown(_a) {
99
103
  noPadding: true,
100
104
  popoverContent: /* @__PURE__ */ React.createElement("form", __spreadProps(__spreadValues({}, filterDOMProps(props, { global: true })), {
101
105
  onSubmit,
102
- className: styles["sapphire-filter-dropdown"]
106
+ className: clsx(styles["sapphire-filter-dropdown"], styleProps.className),
107
+ style: __spreadValues({}, styleProps.style)
103
108
  }), /* @__PURE__ */ React.createElement("div", {
104
109
  className: styles["sapphire-filter-dropdown__body"]
105
110
  }, children), /* @__PURE__ */ React.createElement("div", {
106
111
  className: styles["sapphire-filter-dropdown__footer"]
107
112
  }, /* @__PURE__ */ React.createElement(ButtonGroup, {
108
113
  align: "right"
109
- }, /* @__PURE__ */ React.createElement(Button, {
114
+ }, !hideClearButton && /* @__PURE__ */ React.createElement(Button, {
110
115
  size: buttonSize,
111
116
  variant: "text",
112
117
  onPress: () => {
@@ -1 +1 @@
1
- {"version":3,"file":"FilterDropdown.js","sources":["../../../../src/Filtering/src/FilterDropdown.tsx"],"sourcesContent":["import React, { useRef, ReactNode, FormEvent } from 'react';\nimport { VisuallyHidden } from '@react-aria/visually-hidden';\nimport { useEffectEvent, filterDOMProps } from '@react-aria/utils';\nimport { useControlledState } from '@react-stately/utils';\nimport {\n Button,\n ButtonGroup,\n PopoverTrigger,\n PopoverTriggerProps,\n SapphireStyleProps,\n ToggleButton,\n GlobalDomAttributes,\n} from '@danske/sapphire-react';\nimport { ChevronDown, ChevronUp } from '@danske/sapphire-icons/react';\nimport { FocusableRefValue } from '@react-types/shared';\nimport styles from '@danske/sapphire-css/components/filterDropdown/filterDropdown.module.css';\n\nexport interface FilterDropdownProps\n extends GlobalDomAttributes,\n SapphireStyleProps,\n Pick<\n PopoverTriggerProps,\n 'defaultOpen' | 'isOpen' | 'onOpenChange' | 'noMaxWidth'\n > {\n /**\n * \"Filter by\" label, shown inside the trigger button.\n */\n label: ReactNode;\n /**\n * Filter value, shown inside the trigger button. `null`, `undefined` and empty string are\n * considered as unset value.\n */\n value: ReactNode;\n /**\n * Filtering UI controls, rendered in a popover.\n */\n children: ReactNode;\n /**\n * Called when:\n * - `Enter` is pressed on form fields rendered inside the popover.\n * - 'Apply' button is pressed (if `hasApplyButton` is true)\n */\n onApply?: () => void;\n /**\n * Whether to show the 'Apply' button.\n */\n hasApplyButton?: boolean;\n /**\n * Called when 'Clear' button is pressed.\n */\n onClear?: () => void;\n /**\n * Whether the button is disabled.\n */\n isDisabled?: boolean;\n /**\n * Whether the 'Apply' button is disabled.\n */\n isApplyDisabled?: boolean;\n /**\n * Whether the 'Clear' button is disabled.\n */\n isClearDisabled?: boolean;\n /**\n * The label of the 'Clear' button.\n * @default \"Clear\"\n */\n clearButtonLabel?: ReactNode;\n /**\n * The label of the 'Apply' button.\n * @default \"Apply\"\n */\n applyButtonLabel?: ReactNode;\n /**\n * The size of the buttons incl. the trigger itself.\n * @default 'md'\n */\n buttonSize?: 'sm' | 'md' | 'lg';\n}\n\n/**\n * A button with a dropdown, used for filtering UI.\n */\nexport function FilterDropdown({\n children,\n label,\n value,\n isDisabled = false,\n isApplyDisabled = false,\n isClearDisabled,\n isOpen: isOpenProp,\n applyButtonLabel = 'Apply',\n clearButtonLabel = 'Clear',\n defaultOpen = false,\n hasApplyButton = false,\n noMaxWidth,\n onApply,\n onClear,\n onOpenChange,\n buttonSize = 'md',\n ...props\n}: FilterDropdownProps): JSX.Element {\n const triggerRef = useRef<FocusableRefValue>(null);\n\n // We need to know if the dropdown is open or not, so we control the state here, still\n // allowing for both controlled and uncontrolled modes.\n const [isOpen, setIsOpen] = useControlledState(\n isOpenProp,\n defaultOpen,\n useEffectEvent(onOpenChange)\n );\n const hasValue = value != null && value !== '';\n const close = () => setIsOpen(false);\n const onSubmit = (e: FormEvent) => {\n e.preventDefault();\n onApply?.();\n close();\n // We need to manually restore focus to trigger as apply button is a form submit button\n triggerRef.current?.focus();\n };\n\n const applyButton = (\n <Button\n type=\"submit\"\n size={buttonSize}\n excludeFromTabOrder={!hasApplyButton}\n isDisabled={isApplyDisabled}\n >\n {applyButtonLabel}\n </Button>\n );\n\n return (\n <PopoverTrigger\n ref={triggerRef}\n placement=\"bottom left\"\n isOpen={isOpen}\n onOpenChange={setIsOpen}\n noMaxWidth={noMaxWidth}\n noPadding\n popoverContent={\n <form\n {...filterDOMProps(props, { global: true })}\n onSubmit={onSubmit}\n className={styles['sapphire-filter-dropdown']}\n >\n <div className={styles['sapphire-filter-dropdown__body']}>\n {children}\n </div>\n <div className={styles['sapphire-filter-dropdown__footer']}>\n <ButtonGroup align=\"right\">\n <Button\n size={buttonSize}\n variant=\"text\"\n onPress={() => {\n close();\n onClear?.();\n }}\n isDisabled={isClearDisabled ?? !hasValue}\n >\n {clearButtonLabel}\n </Button>\n {hasApplyButton ? (\n applyButton\n ) : (\n // The following is necessary to have the form submitted on \"Enter\", if there is more than one field\n <VisuallyHidden>{applyButton}</VisuallyHidden>\n )}\n </ButtonGroup>\n </div>\n </form>\n }\n >\n <ToggleButton\n icon={isOpen ? <ChevronUp /> : <ChevronDown />}\n iconAlign=\"right\"\n isSelected={hasValue}\n isDisabled={isDisabled}\n size={buttonSize}\n >\n {label}\n {value ? ': ' : ''}\n {value}\n </ToggleButton>\n </PopoverTrigger>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"FilterDropdown.js","sources":["../../../../src/Filtering/src/FilterDropdown.tsx"],"sourcesContent":["import React, { useRef, ReactNode, FormEvent } from 'react';\nimport clsx from 'clsx';\nimport { VisuallyHidden } from '@react-aria/visually-hidden';\nimport { useEffectEvent, filterDOMProps } from '@react-aria/utils';\nimport { useControlledState } from '@react-stately/utils';\nimport {\n Button,\n ButtonGroup,\n PopoverTrigger,\n PopoverTriggerProps,\n SapphireStyleProps,\n ToggleButton,\n GlobalDomAttributes,\n useSapphireStyleProps,\n} from '@danske/sapphire-react';\nimport { ChevronDown, ChevronUp } from '@danske/sapphire-icons/react';\nimport { FocusableRefValue } from '@react-types/shared';\nimport styles from '@danske/sapphire-css/components/filterDropdown/filterDropdown.module.css';\n\nexport interface FilterDropdownProps\n extends GlobalDomAttributes,\n SapphireStyleProps,\n Pick<\n PopoverTriggerProps,\n 'defaultOpen' | 'isOpen' | 'onOpenChange' | 'noMaxWidth'\n > {\n /**\n * \"Filter by\" label, shown inside the trigger button.\n */\n label: ReactNode;\n /**\n * Filter value, shown inside the trigger button. `null`, `undefined` and empty string are\n * considered as unset value.\n */\n value: ReactNode;\n /**\n * Filtering UI controls, rendered in a popover.\n */\n children: ReactNode;\n /**\n * Called when:\n * - `Enter` is pressed on form fields rendered inside the popover.\n * - 'Apply' button is pressed (if `hasApplyButton` is true)\n */\n onApply?: () => void;\n /**\n * Whether to show the 'Apply' button.\n */\n hasApplyButton?: boolean;\n /**\n * Called when 'Clear' button is pressed.\n */\n onClear?: () => void;\n /**\n * Whether the button is disabled.\n */\n isDisabled?: boolean;\n /**\n * Whether the 'Apply' button is disabled.\n */\n isApplyDisabled?: boolean;\n /**\n * Whether the 'Clear' button is hidden.\n */\n hideClearButton?: boolean;\n /**\n * Whether the 'Clear' button is disabled.\n */\n isClearDisabled?: boolean;\n /**\n * The label of the 'Clear' button.\n * @default \"Clear\"\n */\n clearButtonLabel?: ReactNode;\n /**\n * The label of the 'Apply' button.\n * @default \"Apply\"\n */\n applyButtonLabel?: ReactNode;\n /**\n * The size of the buttons incl. the trigger itself.\n * @default 'md'\n */\n buttonSize?: 'sm' | 'md' | 'lg';\n}\n\n/**\n * A button with a dropdown, used for filtering UI.\n */\nexport function FilterDropdown({\n children,\n label,\n value,\n isDisabled = false,\n isApplyDisabled = false,\n isClearDisabled,\n isOpen: isOpenProp,\n applyButtonLabel = 'Apply',\n clearButtonLabel = 'Clear',\n hideClearButton = false,\n defaultOpen = false,\n hasApplyButton = false,\n noMaxWidth,\n onApply,\n onClear,\n onOpenChange,\n buttonSize = 'md',\n ...props\n}: FilterDropdownProps): JSX.Element {\n const triggerRef = useRef<FocusableRefValue>(null);\n const { styleProps } = useSapphireStyleProps(props);\n\n // We need to know if the dropdown is open or not, so we control the state here, still\n // allowing for both controlled and uncontrolled modes.\n const [isOpen, setIsOpen] = useControlledState(\n isOpenProp,\n defaultOpen,\n useEffectEvent(onOpenChange)\n );\n const hasValue = value != null && value !== '';\n const close = () => setIsOpen(false);\n const onSubmit = (e: FormEvent) => {\n e.preventDefault();\n onApply?.();\n close();\n // We need to manually restore focus to trigger as apply button is a form submit button\n triggerRef.current?.focus();\n };\n\n const applyButton = (\n <Button\n type=\"submit\"\n size={buttonSize}\n excludeFromTabOrder={!hasApplyButton}\n isDisabled={isApplyDisabled}\n >\n {applyButtonLabel}\n </Button>\n );\n\n return (\n <PopoverTrigger\n ref={triggerRef}\n placement=\"bottom left\"\n isOpen={isOpen}\n onOpenChange={setIsOpen}\n noMaxWidth={noMaxWidth}\n noPadding\n popoverContent={\n <form\n {...filterDOMProps(props, { global: true })}\n onSubmit={onSubmit}\n className={clsx(\n styles['sapphire-filter-dropdown'],\n styleProps.className\n )}\n style={{ ...styleProps.style }}\n >\n <div className={styles['sapphire-filter-dropdown__body']}>\n {children}\n </div>\n <div className={styles['sapphire-filter-dropdown__footer']}>\n <ButtonGroup align=\"right\">\n {!hideClearButton && (\n <Button\n size={buttonSize}\n variant=\"text\"\n onPress={() => {\n close();\n onClear?.();\n }}\n isDisabled={isClearDisabled ?? !hasValue}\n >\n {clearButtonLabel}\n </Button>\n )}\n {hasApplyButton ? (\n applyButton\n ) : (\n // The following is necessary to have the form submitted on \"Enter\", if there is more than one field\n <VisuallyHidden>{applyButton}</VisuallyHidden>\n )}\n </ButtonGroup>\n </div>\n </form>\n }\n >\n <ToggleButton\n icon={isOpen ? <ChevronUp /> : <ChevronDown />}\n iconAlign=\"right\"\n isSelected={hasValue}\n isDisabled={isDisabled}\n size={buttonSize}\n >\n {label}\n {value ? ': ' : ''}\n {value}\n </ToggleButton>\n </PopoverTrigger>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -5,8 +5,9 @@ import '@danske/sapphire-icons/react';
5
5
  import '@danske/sapphire-css/components/alert/alert.module.css';
6
6
  import 'clsx';
7
7
  import { mergeRefs } from '@react-aria/utils';
8
- import '@react-aria/combobox';
9
8
  import '@react-aria/i18n';
9
+ import '@danske/sapphire-css/components/amount/amount.module.css';
10
+ import '@react-aria/combobox';
10
11
  import '@react-spectrum/utils';
11
12
  import '../../Breadcrumbs/src/Breadcrumbs.js';
12
13
  import '../../Breadcrumbs/src/BreadcrumbItem.js';
@@ -1 +1 @@
1
- {"version":3,"file":"SearchableSelectFilter.js","sources":["../../../../src/Filtering/src/SearchableSelectFilter.tsx"],"sourcesContent":["import React, { cloneElement, ReactElement, useRef } from 'react';\nimport {\n Flex,\n ListBoxProps,\n SapphireStyleProps,\n SearchFieldPropsWithRef,\n tokens,\n GlobalDomAttributes,\n} from '@danske/sapphire-react';\nimport { FilterDropdown, FilterDropdownProps } from '../..';\nimport { mergeRefs } from '@react-aria/utils';\nimport { useControlledState } from '@react-stately/utils';\n\nexport interface SearchableSelectFilterProps\n extends GlobalDomAttributes,\n SapphireStyleProps,\n Omit<FilterDropdownProps, 'children'> {\n /**\n * The SearchField to search items with.\n */\n searchField: ReactElement<SearchFieldPropsWithRef<object>>;\n /**\n * The ListBox to select items from.\n */\n listBox: ReactElement<ListBoxProps<object>>;\n /**\n * The Button size of the trigger\n * @default 'md'\n */\n size?: 'sm' | 'md' | 'lg';\n}\n\n/**\n * A button with a dropdown, used for filtering UI.\n */\nexport function SearchableSelectFilter(\n props: SearchableSelectFilterProps\n): JSX.Element {\n const { searchField, listBox, size = 'md', ...otherProps } = props;\n const searchFieldRef = useRef<HTMLInputElement>(null);\n\n const searchFieldProps = searchField.props;\n const listBoxProps = listBox.props;\n\n const [searchQuery, setSearchQuery] = useControlledState(\n searchFieldProps?.value,\n '',\n searchFieldProps.onChange\n );\n\n if (\n listBoxProps.connectedInputRef &&\n typeof process !== 'undefined' &&\n process.env?.NODE_ENV === 'development'\n ) {\n // eslint-disable-next-line no-console\n console.warn(\n 'The connectedInputRef prop on the ListBox in the SearchableSelectFilter component is not needed and will be ignored. The connectedInputRef is set automatically (to the passed SearchField) and should not be set manually.'\n );\n }\n\n const hasSelection =\n listBoxProps.selectedKeys === 'all' ||\n Array.from(listBoxProps.selectedKeys || []).length > 0;\n\n return (\n <FilterDropdown\n {...otherProps}\n noMaxWidth={otherProps.noMaxWidth ?? true}\n buttonSize={size}\n // Since useCollectionFocusProxy disables normal form submission behaviour on \"Enter\"\n // the apply button is the only way to submit, which is why we add it if an onApply function is passed\n hasApplyButton={Boolean(otherProps.onApply)}\n // In scenarios where selections are not applied immediately we want to allow cancelling\n // the filter selection via 'Clear' button as soon as at least 1 item is selected\n isClearDisabled={\n otherProps.isClearDisabled || (!hasSelection && !otherProps.value)\n }\n >\n <Flex flexDirection=\"column\" height=\"100%\">\n {cloneElement(searchField, {\n size: 'md',\n value: searchFieldProps.value || searchQuery,\n inputRef: mergeRefs(searchFieldRef, searchFieldProps.inputRef),\n width: searchFieldProps.width || '100%',\n marginBottom: searchFieldProps.marginBottom || tokens.size.spacingSm,\n onChange: setSearchQuery,\n })}\n {cloneElement(listBox, {\n connectedInputRef: searchFieldRef,\n selectionMode: listBoxProps.selectionMode || 'multiple',\n marginX: `calc(${tokens.size.spacingContainerHorizontalSm.value} * -1)`,\n hasScrollDividers: true,\n filter:\n // This is a way to also allow opting out of the internal filter with filter={undefined}\n // without us having to allow for more values on the ListBox filter prop\n 'filter' in listBoxProps\n ? listBoxProps.filter\n : (textValue: string) =>\n textValue.toLowerCase().includes(searchQuery.toLowerCase()),\n })}\n </Flex>\n </FilterDropdown>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SearchableSelectFilter.js","sources":["../../../../src/Filtering/src/SearchableSelectFilter.tsx"],"sourcesContent":["import React, { cloneElement, ReactElement, useRef } from 'react';\nimport {\n Flex,\n ListBoxProps,\n SapphireStyleProps,\n SearchFieldPropsWithRef,\n tokens,\n GlobalDomAttributes,\n} from '@danske/sapphire-react';\nimport { FilterDropdown, FilterDropdownProps } from '../..';\nimport { mergeRefs } from '@react-aria/utils';\nimport { useControlledState } from '@react-stately/utils';\n\nexport interface SearchableSelectFilterProps\n extends GlobalDomAttributes,\n SapphireStyleProps,\n Omit<FilterDropdownProps, 'children'> {\n /**\n * The SearchField to search items with.\n */\n searchField: ReactElement<SearchFieldPropsWithRef<object>>;\n /**\n * The ListBox to select items from.\n */\n listBox: ReactElement<ListBoxProps<object>>;\n /**\n * The Button size of the trigger\n * @default 'md'\n */\n size?: 'sm' | 'md' | 'lg';\n}\n\n/**\n * A button with a dropdown, used for filtering UI.\n */\nexport function SearchableSelectFilter(\n props: SearchableSelectFilterProps\n): JSX.Element {\n const { searchField, listBox, size = 'md', ...otherProps } = props;\n const searchFieldRef = useRef<HTMLInputElement>(null);\n\n const searchFieldProps = searchField.props;\n const listBoxProps = listBox.props;\n\n const [searchQuery, setSearchQuery] = useControlledState(\n searchFieldProps?.value,\n '',\n searchFieldProps.onChange\n );\n\n if (\n listBoxProps.connectedInputRef &&\n typeof process !== 'undefined' &&\n process.env?.NODE_ENV === 'development'\n ) {\n // eslint-disable-next-line no-console\n console.warn(\n 'The connectedInputRef prop on the ListBox in the SearchableSelectFilter component is not needed and will be ignored. The connectedInputRef is set automatically (to the passed SearchField) and should not be set manually.'\n );\n }\n\n const hasSelection =\n listBoxProps.selectedKeys === 'all' ||\n Array.from(listBoxProps.selectedKeys || []).length > 0;\n\n return (\n <FilterDropdown\n {...otherProps}\n noMaxWidth={otherProps.noMaxWidth ?? true}\n buttonSize={size}\n // Since useCollectionFocusProxy disables normal form submission behaviour on \"Enter\"\n // the apply button is the only way to submit, which is why we add it if an onApply function is passed\n hasApplyButton={Boolean(otherProps.onApply)}\n // In scenarios where selections are not applied immediately we want to allow cancelling\n // the filter selection via 'Clear' button as soon as at least 1 item is selected\n isClearDisabled={\n otherProps.isClearDisabled || (!hasSelection && !otherProps.value)\n }\n >\n <Flex flexDirection=\"column\" height=\"100%\">\n {cloneElement(searchField, {\n size: 'md',\n value: searchFieldProps.value || searchQuery,\n inputRef: mergeRefs(searchFieldRef, searchFieldProps.inputRef),\n width: searchFieldProps.width || '100%',\n marginBottom: searchFieldProps.marginBottom || tokens.size.spacingSm,\n onChange: setSearchQuery,\n })}\n {cloneElement(listBox, {\n connectedInputRef: searchFieldRef,\n selectionMode: listBoxProps.selectionMode || 'multiple',\n marginX: `calc(${tokens.size.spacingContainerHorizontalSm.value} * -1)`,\n hasScrollDividers: true,\n filter:\n // This is a way to also allow opting out of the internal filter with filter={undefined}\n // without us having to allow for more values on the ListBox filter prop\n 'filter' in listBoxProps\n ? listBoxProps.filter\n : (textValue: string) =>\n textValue.toLowerCase().includes(searchQuery.toLowerCase()),\n })}\n </Flex>\n </FilterDropdown>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCO,SAAA,sBAAA,CACL,KACa,EAAA;AArCf,EAAA,IAAA,EAAA,EAAA,EAAA,CAAA;AAsCE,EAA6D,MAAA,EAAA,GAAA,KAAA,EAArD,EAAa,WAAA,EAAA,OAAA,EAAS,IAAO,GAAA,IAAA,EAAA,GAAwB,IAAf,UAAe,GAAA,SAAA,CAAA,EAAA,EAAf,CAAtC,aAAA,EAAa,SAAS,EAAA,MAAA,CAAA,CAAA,CAAA;AAC9B,EAAA,MAAM,iBAAiB,MAAyB,CAAA,IAAA,CAAA,CAAA;AAEhD,EAAA,MAAM,mBAAmB,WAAY,CAAA,KAAA,CAAA;AACrC,EAAA,MAAM,eAAe,OAAQ,CAAA,KAAA,CAAA;AAE7B,EAAA,MAAM,CAAC,WAAa,EAAA,cAAA,CAAA,GAAkB,mBACpC,gBAAkB,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,gBAAA,CAAA,KAAA,EAClB,IACA,gBAAiB,CAAA,QAAA,CAAA,CAAA;AAGnB,EACE,IAAA,YAAA,CAAa,qBACb,OAAO,OAAA,KAAY,eACnB,CAAQ,CAAA,EAAA,GAAA,OAAA,CAAA,GAAA,KAAR,IAAa,GAAA,KAAA,CAAA,GAAA,EAAA,CAAA,QAAA,MAAa,aAC1B,EAAA;AAEA,IAAA,OAAA,CAAQ,IACN,CAAA,6NAAA,CAAA,CAAA;AAAA,GAAA;AAIJ,EAAM,MAAA,YAAA,GACJ,aAAa,YAAiB,KAAA,KAAA,IAC9B,MAAM,IAAK,CAAA,YAAA,CAAa,YAAgB,IAAA,EAAA,CAAA,CAAI,MAAS,GAAA,CAAA,CAAA;AAEvD,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,cAAD,EAAA,aAAA,CAAA,cAAA,CAAA,EAAA,EACM,UADN,CAAA,EAAA;AAAA,IAEE,UAAA,EAAY,CAAW,EAAA,GAAA,UAAA,CAAA,UAAA,KAAX,IAAyB,GAAA,EAAA,GAAA,IAAA;AAAA,IACrC,UAAY,EAAA,IAAA;AAAA,IAGZ,cAAA,EAAgB,QAAQ,UAAW,CAAA,OAAA,CAAA;AAAA,IAGnC,iBACE,UAAW,CAAA,eAAA,IAAoB,CAAC,YAAA,IAAgB,CAAC,UAAW,CAAA,KAAA;AAAA,GAAA,CAAA,sCAG7D,IAAD,EAAA;AAAA,IAAM,aAAc,EAAA,QAAA;AAAA,IAAS,MAAO,EAAA,MAAA;AAAA,GAAA,EACjC,aAAa,WAAa,EAAA;AAAA,IACzB,IAAM,EAAA,IAAA;AAAA,IACN,KAAA,EAAO,iBAAiB,KAAS,IAAA,WAAA;AAAA,IACjC,QAAA,EAAU,SAAU,CAAA,cAAA,EAAgB,gBAAiB,CAAA,QAAA,CAAA;AAAA,IACrD,KAAA,EAAO,iBAAiB,KAAS,IAAA,MAAA;AAAA,IACjC,YAAc,EAAA,gBAAA,CAAiB,YAAgB,IAAA,MAAA,CAAO,IAAK,CAAA,SAAA;AAAA,IAC3D,QAAU,EAAA,cAAA;AAAA,GAAA,CAAA,EAEX,aAAa,OAAS,EAAA;AAAA,IACrB,iBAAmB,EAAA,cAAA;AAAA,IACnB,aAAA,EAAe,aAAa,aAAiB,IAAA,UAAA;AAAA,IAC7C,OAAS,EAAA,CAAA,KAAA,EAAQ,MAAO,CAAA,IAAA,CAAK,4BAA6B,CAAA,KAAA,CAAA,MAAA,CAAA;AAAA,IAC1D,iBAAmB,EAAA,IAAA;AAAA,IACnB,MAAA,EAGE,QAAY,IAAA,YAAA,GACR,YAAa,CAAA,MAAA,GACb,CAAC,SACC,KAAA,SAAA,CAAU,WAAc,EAAA,CAAA,QAAA,CAAS,WAAY,CAAA,WAAA,EAAA,CAAA;AAAA,GAAA,CAAA,CAAA,CAAA,CAAA;AAAA;;;;"}
@@ -1,14 +1,15 @@
1
- import React, { forwardRef, useRef, useImperativeHandle } from 'react';
1
+ import React, { forwardRef, useMemo, useRef, useImperativeHandle } from 'react';
2
2
  import clsx from 'clsx';
3
3
  import { useFocusRing } from '@react-aria/focus';
4
- import { useMessageFormatter } from '@react-aria/i18n';
4
+ import { useMessageFormatter, useLocale } from '@react-aria/i18n';
5
5
  import { useObjectRef, mergeProps } from '@react-aria/utils';
6
6
  import { createFocusableRef } from '@react-spectrum/utils';
7
7
  import textFieldStyles from '@danske/sapphire-css/components/textField/textField.module.css';
8
- import { useThemeCheck, Field, Label } from '@danske/sapphire-react';
8
+ import { useThemeCheck, Field, Label, Separator } from '@danske/sapphire-react';
9
9
  import intlMessages from '../i18n/index.js';
10
10
  import { StepperButton } from './StepperButton.js';
11
11
  import { useAutofillStyle } from './useAutofillStyle.js';
12
+ import { useNumberFieldFormatting } from './useNumberFieldFormatting.js';
12
13
  import { useSapphireNumberField } from './useSapphireNumberField.js';
13
14
 
14
15
  var __defProp = Object.defineProperty;
@@ -43,6 +44,7 @@ var __objRest = (source, exclude) => {
43
44
  return target;
44
45
  };
45
46
  const NumberField = forwardRef(function NumberField2(props, ref) {
47
+ var _b;
46
48
  const _a = props, {
47
49
  label,
48
50
  isDisabled,
@@ -50,15 +52,15 @@ const NumberField = forwardRef(function NumberField2(props, ref) {
50
52
  note,
51
53
  isRequired,
52
54
  contextualHelp,
53
- prefix,
54
- postfix,
55
+ affix = "auto",
55
56
  size = "lg",
56
57
  labelPlacement = "above",
57
58
  necessityIndicator = false,
58
59
  alignInputRight,
59
60
  showButtons = false,
60
61
  incrementAriaLabel,
61
- decrementAriaLabel
62
+ decrementAriaLabel,
63
+ autoFormat = false
62
64
  } = _a, otherProps = __objRest(_a, [
63
65
  "label",
64
66
  "isDisabled",
@@ -66,16 +68,22 @@ const NumberField = forwardRef(function NumberField2(props, ref) {
66
68
  "note",
67
69
  "isRequired",
68
70
  "contextualHelp",
69
- "prefix",
70
- "postfix",
71
+ "affix",
71
72
  "size",
72
73
  "labelPlacement",
73
74
  "necessityIndicator",
74
75
  "alignInputRight",
75
76
  "showButtons",
76
77
  "incrementAriaLabel",
77
- "decrementAriaLabel"
78
+ "decrementAriaLabel",
79
+ "autoFormat"
78
80
  ]);
81
+ const { prefix, postfix } = useMemo(() => {
82
+ if (affix === "auto") {
83
+ return { prefix: void 0, postfix: void 0 };
84
+ }
85
+ return { prefix: affix.prefix, postfix: affix.postfix };
86
+ }, [affix]);
79
87
  useThemeCheck();
80
88
  const inputRef = useObjectRef(props.inputRef);
81
89
  const formatMessage = useMessageFormatter(intlMessages);
@@ -92,6 +100,24 @@ const NumberField = forwardRef(function NumberField2(props, ref) {
92
100
  }), inputRef);
93
101
  const { focusProps, isFocusVisible } = useFocusRing();
94
102
  const { autofillStyles, updateStyle } = useAutofillStyle(inputRef);
103
+ const { locale } = useLocale();
104
+ const formatter = useMemo(() => new Intl.NumberFormat(locale, props.formatOptions), [locale, props.formatOptions]);
105
+ const formattingResult = useNumberFieldFormatting({
106
+ inputRef,
107
+ formatter,
108
+ inputValue: inputProps.value,
109
+ prefix,
110
+ postfix,
111
+ onOriginalKeyDown: inputProps.onKeyDown,
112
+ onChange: props.onChange,
113
+ autoFormat
114
+ });
115
+ const { extractedPrefix, extractedPostfix, handleInput, handleKeyDown } = autoFormat ? formattingResult : {
116
+ extractedPrefix: formattingResult.extractedPrefix,
117
+ extractedPostfix: formattingResult.extractedPostfix,
118
+ handleInput: void 0,
119
+ handleKeyDown: inputProps.onKeyDown
120
+ };
95
121
  const containerRef = useRef(null);
96
122
  useImperativeHandle(ref, () => __spreadProps(__spreadValues({}, createFocusableRef(containerRef, inputRef)), {
97
123
  getInputElement() {
@@ -114,32 +140,38 @@ const NumberField = forwardRef(function NumberField2(props, ref) {
114
140
  [textFieldStyles["sapphire-text-field--error"]]: error === true || typeof error === "string",
115
141
  [textFieldStyles["sapphire-text-field--md"]]: size === "md"
116
142
  })
117
- }, prefix && /* @__PURE__ */ React.createElement("span", {
143
+ }, extractedPrefix && /* @__PURE__ */ React.createElement("span", {
118
144
  className: clsx(textFieldStyles["sapphire-text-field__prefix"], {
119
- [textFieldStyles["sapphire-text-field__prefix--icon"]]: typeof prefix !== "string"
145
+ [textFieldStyles["sapphire-text-field__prefix--icon"]]: typeof extractedPrefix !== "string"
120
146
  })
121
- }, prefix), /* @__PURE__ */ React.createElement("input", __spreadProps(__spreadValues({}, mergeProps(inputProps, focusProps, {
147
+ }, extractedPrefix), /* @__PURE__ */ React.createElement("input", __spreadProps(__spreadValues({}, mergeProps(inputProps, focusProps, {
122
148
  onChange: updateStyle,
123
149
  onBlur: updateStyle
124
- })), {
150
+ }, autoFormat ? {
151
+ onInput: handleInput,
152
+ onKeyDown: handleKeyDown
153
+ } : {})), {
154
+ value: (_b = formattingResult == null ? void 0 : formattingResult.displayValue) != null ? _b : inputProps.value,
125
155
  ref: inputRef,
126
156
  className: clsx(textFieldStyles["sapphire-text-field__input"], {
127
157
  [textFieldStyles["sapphire-text-field__input--align-right"]]: !!alignInputRight
128
158
  }),
129
159
  style: autofillStyles
130
- })), postfix && /* @__PURE__ */ React.createElement("span", {
160
+ })), extractedPostfix && /* @__PURE__ */ React.createElement("span", {
131
161
  className: clsx(textFieldStyles["sapphire-text-field__postfix"], {
132
- [textFieldStyles["sapphire-text-field__postfix--icon"]]: typeof postfix !== "string"
162
+ [textFieldStyles["sapphire-text-field__postfix--icon"]]: typeof extractedPostfix !== "string"
133
163
  })
134
- }, postfix), showButtons && /* @__PURE__ */ React.createElement("div", {
135
- className: clsx(textFieldStyles["sapphire-text-field__stepper"])
164
+ }, extractedPostfix), showButtons && /* @__PURE__ */ React.createElement("div", {
165
+ className: textFieldStyles["sapphire-text-field__stepper"]
136
166
  }, /* @__PURE__ */ React.createElement(StepperButton, __spreadValues({
137
- variant: "increment",
138
- size
139
- }, incrementButtonProps)), /* @__PURE__ */ React.createElement(StepperButton, __spreadValues({
140
167
  variant: "decrement",
141
168
  size
142
- }, decrementButtonProps))))), (error && typeof error !== "boolean" || note) && /* @__PURE__ */ React.createElement(Field.Footer, null, error && typeof error !== "boolean" ? /* @__PURE__ */ React.createElement(Field.Note, {
169
+ }, decrementButtonProps)), /* @__PURE__ */ React.createElement(Separator, {
170
+ orientation: "vertical"
171
+ }), /* @__PURE__ */ React.createElement(StepperButton, __spreadValues({
172
+ variant: "increment",
173
+ size
174
+ }, incrementButtonProps))))), (error && typeof error !== "boolean" || note) && /* @__PURE__ */ React.createElement(Field.Footer, null, error && typeof error !== "boolean" ? /* @__PURE__ */ React.createElement(Field.Note, {
143
175
  variant: "error"
144
176
  }, error) : note ? note : /* @__PURE__ */ React.createElement(React.Fragment, null))));
145
177
  });
@@ -1 +1 @@
1
- {"version":3,"file":"NumberField.js","sources":["../../../../src/NumberField/src/NumberField.tsx"],"sourcesContent":["import React, {\n forwardRef,\n ForwardedRef,\n ReactNode,\n RefObject,\n useImperativeHandle,\n useRef,\n} from 'react';\nimport clsx from 'clsx';\nimport { useFocusRing } from '@react-aria/focus';\nimport { useMessageFormatter } from '@react-aria/i18n';\nimport { mergeProps, useObjectRef } from '@react-aria/utils';\nimport { createFocusableRef } from '@react-spectrum/utils';\nimport { FocusableRefValue, PressEvents } from '@react-types/shared';\nimport textFieldStyles from '@danske/sapphire-css/components/textField/textField.module.css';\nimport {\n Field,\n Label,\n SapphireStyleProps,\n useThemeCheck,\n GlobalDomAttributes,\n} from '@danske/sapphire-react';\n\nimport intlMessages from '../i18n';\nimport { StepperButton } from './StepperButton';\nimport { useAutofillStyle } from './useAutofillStyle';\nimport {\n SapphireNumberFieldProps,\n useSapphireNumberField,\n} from './useSapphireNumberField';\n\nexport type NumberFieldRef = FocusableRefValue<\n HTMLInputElement,\n HTMLDivElement\n> & {\n getInputElement(): HTMLInputElement | null;\n};\n\nexport interface NumberFieldProps\n extends SapphireNumberFieldProps,\n PressEvents,\n SapphireStyleProps,\n GlobalDomAttributes {\n prefix?: ReactNode;\n postfix?: ReactNode;\n inputRef?: RefObject<HTMLInputElement | null>;\n /**\n * A note to show below the input.\n * If the input has an error message, this note will be replaced by that.\n */\n note?: ReactNode;\n /**\n * A HelpButton to render next to the label.\n */\n contextualHelp?: ReactNode;\n /**\n * To visually indicate if this field is required or optional.\n * @default false\n */\n necessityIndicator?: boolean;\n /**\n * @default 'lg'\n */\n size?: 'lg' | 'md';\n /**\n * Aligns the text inside the input fields without affecting the positioning of the label of the field.\n */\n alignInputRight?: boolean;\n /**\n * Places the label either above (default) or on the side of the control.\n * @default 'above'\n */\n labelPlacement?: 'side' | 'above';\n /**\n * To show the buttons for incrementing and decrementing the value.\n * @default false\n */\n showButtons?: boolean;\n}\n\nexport const NumberField = forwardRef(function NumberField(\n props: NumberFieldProps,\n ref: ForwardedRef<NumberFieldRef>\n) {\n const {\n label,\n isDisabled,\n error,\n note,\n isRequired,\n contextualHelp,\n prefix,\n postfix,\n size = 'lg',\n labelPlacement = 'above',\n necessityIndicator = false,\n alignInputRight,\n showButtons = false,\n incrementAriaLabel,\n decrementAriaLabel,\n ...otherProps\n } = props;\n useThemeCheck();\n const inputRef = useObjectRef<HTMLInputElement>(props.inputRef);\n const formatMessage = useMessageFormatter(intlMessages);\n const {\n inputProps,\n labelProps,\n incrementButtonProps,\n decrementButtonProps,\n descriptionProps,\n errorMessageProps,\n } = useSapphireNumberField(\n {\n ...props,\n incrementAriaLabel: incrementAriaLabel ?? formatMessage('increment'),\n decrementAriaLabel: decrementAriaLabel ?? formatMessage('decrement'),\n },\n inputRef\n );\n const { focusProps, isFocusVisible } = useFocusRing();\n const { autofillStyles, updateStyle } = useAutofillStyle<'input'>(inputRef);\n\n const containerRef = useRef<HTMLDivElement>(null);\n\n useImperativeHandle(ref, () => ({\n ...createFocusableRef(containerRef, inputRef),\n /**\n * (This function is deprecated. Use `inputRef` prop)\n * @deprecated\n */\n getInputElement() {\n return inputRef.current;\n },\n }));\n\n return (\n <Field\n // otherProps contains some of the same props as inputProps. That is\n // intended, but some DOM props, like \"id\", should not be repeated\n {...removeUniqueDOMProps(otherProps)}\n ref={containerRef}\n size={size}\n labelPlacement={labelPlacement}\n >\n <Field.Context\n descriptionProps={error ? errorMessageProps : descriptionProps}\n >\n {label && (\n <Field.Label>\n <Label\n {...labelProps}\n size={size}\n necessityIndicator={\n isRequired && necessityIndicator\n ? 'required'\n : !isRequired && necessityIndicator\n ? 'optional'\n : undefined\n }\n contextualHelp={contextualHelp}\n >\n {label}\n </Label>\n </Field.Label>\n )}\n <Field.Control>\n <div\n className={clsx(textFieldStyles['sapphire-text-field'], {\n [textFieldStyles['is-focus']]: isFocusVisible,\n [textFieldStyles['sapphire-text-field--error']]:\n error === true || typeof error === 'string',\n [textFieldStyles['sapphire-text-field--md']]: size === 'md',\n })}\n >\n {prefix && (\n <span\n className={clsx(\n textFieldStyles['sapphire-text-field__prefix'],\n {\n [textFieldStyles['sapphire-text-field__prefix--icon']]:\n typeof prefix !== 'string',\n }\n )}\n >\n {prefix}\n </span>\n )}\n <input\n {...mergeProps(inputProps, focusProps, {\n onChange: updateStyle,\n onBlur: updateStyle,\n })}\n ref={inputRef}\n className={clsx(textFieldStyles['sapphire-text-field__input'], {\n [textFieldStyles['sapphire-text-field__input--align-right']]:\n !!alignInputRight,\n })}\n style={autofillStyles}\n />\n {postfix && (\n <span\n className={clsx(\n textFieldStyles['sapphire-text-field__postfix'],\n {\n [textFieldStyles['sapphire-text-field__postfix--icon']]:\n typeof postfix !== 'string',\n }\n )}\n >\n {postfix}\n </span>\n )}\n {showButtons && (\n <div\n className={clsx(\n textFieldStyles['sapphire-text-field__stepper']\n )}\n >\n <StepperButton\n variant=\"increment\"\n size={size}\n {...incrementButtonProps}\n />\n <StepperButton\n variant=\"decrement\"\n size={size}\n {...decrementButtonProps}\n />\n </div>\n )}\n </div>\n </Field.Control>\n {((error && typeof error !== 'boolean') || note) && (\n <Field.Footer>\n {error && typeof error !== 'boolean' ? (\n <Field.Note variant=\"error\">{error}</Field.Note>\n ) : note ? (\n note\n ) : (\n <></>\n )}\n </Field.Footer>\n )}\n </Field.Context>\n </Field>\n );\n});\n\n// Once moved to the core package, this function should be removed and instead consume the one from TextFieldBase.\nconst removeUniqueDOMProps = (props: Record<any, any>): Record<any, any> =>\n Object.fromEntries(\n Object.entries(props).filter(\n ([name]) => name !== 'id' && !name.startsWith('data-')\n )\n );\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"NumberField.js","sources":["../../../../src/NumberField/src/NumberField.tsx"],"sourcesContent":["import React, {\n forwardRef,\n ForwardedRef,\n ReactNode,\n RefObject,\n useImperativeHandle,\n useRef,\n useMemo,\n} from 'react';\nimport clsx from 'clsx';\nimport { useFocusRing } from '@react-aria/focus';\nimport { useLocale, useMessageFormatter } from '@react-aria/i18n';\nimport { mergeProps, useObjectRef } from '@react-aria/utils';\nimport { createFocusableRef } from '@react-spectrum/utils';\nimport { FocusableRefValue, PressEvents } from '@react-types/shared';\nimport textFieldStyles from '@danske/sapphire-css/components/textField/textField.module.css';\nimport {\n Field,\n Label,\n SapphireStyleProps,\n useThemeCheck,\n GlobalDomAttributes,\n Separator,\n} from '@danske/sapphire-react';\n\nimport intlMessages from '../i18n';\nimport { StepperButton } from './StepperButton';\nimport { useAutofillStyle } from './useAutofillStyle';\nimport { useNumberFieldFormatting } from './useNumberFieldFormatting';\nimport {\n SapphireNumberFieldProps,\n useSapphireNumberField,\n} from './useSapphireNumberField';\n\nexport type NumberFieldRef = FocusableRefValue<\n HTMLInputElement,\n HTMLDivElement\n> & {\n getInputElement(): HTMLInputElement | null;\n};\n\nexport interface NumberFieldProps\n extends SapphireNumberFieldProps,\n PressEvents,\n SapphireStyleProps,\n GlobalDomAttributes {\n /**\n * A string or element to show before / after the input value.\n *\n * By default (`'auto'`), the component will automatically extract currency/unit symbols\n * from the locale formatter and display them as prefix/postfix.\n * If you provide a custom prefix or postfix, those will be used instead and\n * the extracted symbols will be ignored.\n *\n * @default 'auto' - automatically extracts currency/unit symbols from locale formatter\n */\n affix?: 'auto' | { prefix?: ReactNode; postfix?: ReactNode };\n inputRef?: RefObject<HTMLInputElement | null>;\n /**\n * A note to show below the input.\n * If the input has an error message, this note will be replaced by that.\n */\n note?: ReactNode;\n /**\n * A HelpButton to render next to the label.\n */\n contextualHelp?: ReactNode;\n /**\n * To visually indicate if this field is required or optional.\n * @default false\n */\n necessityIndicator?: boolean;\n /**\n * @default 'lg'\n */\n size?: 'lg' | 'md';\n /**\n * Aligns the text inside the input fields without affecting the positioning of the label of the field.\n */\n alignInputRight?: boolean;\n /**\n * Places the label either above (default) or on the side of the control.\n * @default 'above'\n */\n labelPlacement?: 'side' | 'above';\n /**\n * To show the buttons for incrementing and decrementing the value.\n * @default false\n */\n showButtons?: boolean;\n /**\n * Enables automatic formatting of the input value as the user types, based on the provided formatter and affix.\n *\n * @default false\n */\n autoFormat?: boolean;\n}\n\nexport const NumberField = forwardRef(function NumberField(\n props: NumberFieldProps,\n ref: ForwardedRef<NumberFieldRef>\n) {\n const {\n label,\n isDisabled,\n error,\n note,\n isRequired,\n contextualHelp,\n affix = 'auto',\n size = 'lg',\n labelPlacement = 'above',\n necessityIndicator = false,\n alignInputRight,\n showButtons = false,\n incrementAriaLabel,\n decrementAriaLabel,\n autoFormat = false,\n ...otherProps\n } = props;\n\n // Extract prefix and postfix from affix prop\n const { prefix, postfix } = useMemo(() => {\n if (affix === 'auto') {\n return { prefix: undefined, postfix: undefined };\n }\n return { prefix: affix.prefix, postfix: affix.postfix };\n }, [affix]);\n useThemeCheck();\n const inputRef = useObjectRef<HTMLInputElement>(props.inputRef);\n const formatMessage = useMessageFormatter(intlMessages);\n\n const {\n inputProps,\n labelProps,\n incrementButtonProps,\n decrementButtonProps,\n descriptionProps,\n errorMessageProps,\n } = useSapphireNumberField(\n {\n ...props,\n incrementAriaLabel: incrementAriaLabel ?? formatMessage('increment'),\n decrementAriaLabel: decrementAriaLabel ?? formatMessage('decrement'),\n },\n inputRef\n );\n const { focusProps, isFocusVisible } = useFocusRing();\n const { autofillStyles, updateStyle } = useAutofillStyle<'input'>(inputRef);\n const { locale } = useLocale();\n\n const formatter = useMemo(\n () => new Intl.NumberFormat(locale, props.formatOptions),\n [locale, props.formatOptions]\n );\n\n const formattingResult = useNumberFieldFormatting({\n inputRef,\n formatter,\n inputValue: inputProps.value as string,\n prefix,\n postfix,\n onOriginalKeyDown: inputProps.onKeyDown,\n onChange: props.onChange,\n autoFormat,\n });\n\n const { extractedPrefix, extractedPostfix, handleInput, handleKeyDown } =\n autoFormat\n ? formattingResult\n : {\n extractedPrefix: formattingResult.extractedPrefix,\n extractedPostfix: formattingResult.extractedPostfix,\n handleInput: undefined,\n handleKeyDown: inputProps.onKeyDown,\n };\n\n const containerRef = useRef<HTMLDivElement>(null);\n\n useImperativeHandle(ref, () => ({\n ...createFocusableRef(containerRef, inputRef),\n /**\n * (This function is deprecated. Use `inputRef` prop)\n * @deprecated\n */\n getInputElement() {\n return inputRef.current;\n },\n }));\n\n return (\n <Field\n // otherProps contains some of the same props as inputProps. That is\n // intended, but some DOM props, like \"id\", should not be repeated\n {...removeUniqueDOMProps(otherProps)}\n ref={containerRef}\n size={size}\n labelPlacement={labelPlacement}\n >\n <Field.Context\n descriptionProps={error ? errorMessageProps : descriptionProps}\n >\n {label && (\n <Field.Label>\n <Label\n {...labelProps}\n size={size}\n necessityIndicator={\n isRequired && necessityIndicator\n ? 'required'\n : !isRequired && necessityIndicator\n ? 'optional'\n : undefined\n }\n contextualHelp={contextualHelp}\n >\n {label}\n </Label>\n </Field.Label>\n )}\n <Field.Control>\n <div\n className={clsx(textFieldStyles['sapphire-text-field'], {\n [textFieldStyles['is-focus']]: isFocusVisible,\n [textFieldStyles['sapphire-text-field--error']]:\n error === true || typeof error === 'string',\n [textFieldStyles['sapphire-text-field--md']]: size === 'md',\n })}\n >\n {extractedPrefix && (\n <span\n className={clsx(\n textFieldStyles['sapphire-text-field__prefix'],\n {\n [textFieldStyles['sapphire-text-field__prefix--icon']]:\n typeof extractedPrefix !== 'string',\n }\n )}\n >\n {extractedPrefix}\n </span>\n )}\n <input\n {...mergeProps(\n inputProps,\n focusProps,\n {\n onChange: updateStyle,\n onBlur: updateStyle,\n },\n autoFormat\n ? {\n onInput: handleInput,\n onKeyDown: handleKeyDown,\n }\n : {}\n )}\n value={formattingResult?.displayValue ?? inputProps.value}\n ref={inputRef}\n className={clsx(textFieldStyles['sapphire-text-field__input'], {\n [textFieldStyles['sapphire-text-field__input--align-right']]:\n !!alignInputRight,\n })}\n style={autofillStyles}\n />\n {extractedPostfix && (\n <span\n className={clsx(\n textFieldStyles['sapphire-text-field__postfix'],\n {\n [textFieldStyles['sapphire-text-field__postfix--icon']]:\n typeof extractedPostfix !== 'string',\n }\n )}\n >\n {extractedPostfix}\n </span>\n )}\n {showButtons && (\n <div className={textFieldStyles['sapphire-text-field__stepper']}>\n <StepperButton\n variant=\"decrement\"\n size={size}\n {...decrementButtonProps}\n />\n <Separator orientation=\"vertical\" />\n <StepperButton\n variant=\"increment\"\n size={size}\n {...incrementButtonProps}\n />\n </div>\n )}\n </div>\n </Field.Control>\n {((error && typeof error !== 'boolean') || note) && (\n <Field.Footer>\n {error && typeof error !== 'boolean' ? (\n <Field.Note variant=\"error\">{error}</Field.Note>\n ) : note ? (\n note\n ) : (\n <></>\n )}\n </Field.Footer>\n )}\n </Field.Context>\n </Field>\n );\n});\n\n// Once moved to the core package, this function should be removed and instead consume the one from TextFieldBase.\nconst removeUniqueDOMProps = (props: Record<any, any>): Record<any, any> =>\n Object.fromEntries(\n Object.entries(props).filter(\n ([name]) => name !== 'id' && !name.startsWith('data-')\n )\n );\n"],"names":[],"mappings":"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"}