@olenbetong/appframe-ds 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/package.json +1 -1
  3. package/scripts/copyAssets.mjs +8 -0
  4. package/src/index.ts +3 -0
  5. package/src/layout/AppLayoutDesktop.tsx +3 -0
  6. package/src/layout/AppLayoutMobile.tsx +3 -0
  7. package/src/layout/AppMenu.css +1 -0
  8. package/src/layout/PageContainer.tsx +6 -0
  9. package/src/layout/index.tsx +5 -0
  10. package/src/list/ItemList.css +30 -0
  11. package/src/list/ItemList.tsx +52 -0
  12. package/src/list/ItemListItem.tsx +41 -0
  13. package/src/list/ItemListItemText.tsx +23 -0
  14. package/src/list/index.ts +3 -0
  15. package/src/page/Page.css +45 -0
  16. package/src/page/Page.tsx +70 -0
  17. package/src/page/PageBlock.css +59 -0
  18. package/src/page/PageBlock.tsx +78 -0
  19. package/src/page/PageHeader.css +148 -0
  20. package/src/page/PageHeader.tsx +184 -0
  21. package/src/page/index.ts +3 -0
  22. package/src/paper/Paper.css +35 -0
  23. package/src/paper/Paper.tsx +50 -0
  24. package/src/paper/index.ts +1 -0
  25. package/es/AfLookup/BoundLookup.d.ts +0 -10
  26. package/es/AfLookup/BoundLookup.js +0 -16
  27. package/es/AfLookup/Combobox.css +0 -78
  28. package/es/AfLookup/Combobox.d.ts +0 -32
  29. package/es/AfLookup/Combobox.js +0 -76
  30. package/es/AfLookup/Lookup.css +0 -125
  31. package/es/AfLookup/Lookup.d.ts +0 -35
  32. package/es/AfLookup/Lookup.js +0 -59
  33. package/es/AfLookup/LookupEdit.d.ts +0 -21
  34. package/es/AfLookup/LookupEdit.js +0 -49
  35. package/es/AfLookup/LookupGrid.css +0 -57
  36. package/es/AfLookup/LookupGrid.d.ts +0 -13
  37. package/es/AfLookup/LookupGrid.js +0 -27
  38. package/es/AfLookup/index.d.ts +0 -5
  39. package/es/AfLookup/index.js +0 -5
  40. package/es/binding/BoundCheckbox.d.ts +0 -9
  41. package/es/binding/BoundCheckbox.js +0 -13
  42. package/es/binding/BoundDatePicker.d.ts +0 -7
  43. package/es/binding/BoundDatePicker.js +0 -12
  44. package/es/binding/BoundDateTimePicker.d.ts +0 -7
  45. package/es/binding/BoundDateTimePicker.js +0 -14
  46. package/es/binding/BoundInput.d.ts +0 -6
  47. package/es/binding/BoundInput.js +0 -12
  48. package/es/binding/BoundNumericTextField.d.ts +0 -20
  49. package/es/binding/BoundNumericTextField.js +0 -58
  50. package/es/binding/BoundSelect.d.ts +0 -9
  51. package/es/binding/BoundSelect.js +0 -13
  52. package/es/binding/BoundSwitch.d.ts +0 -9
  53. package/es/binding/BoundSwitch.js +0 -13
  54. package/es/binding/BoundTextField.d.ts +0 -7
  55. package/es/binding/BoundTextField.js +0 -22
  56. package/es/binding/CancelButton.d.ts +0 -3
  57. package/es/binding/CancelButton.js +0 -14
  58. package/es/binding/CancelIconButton.d.ts +0 -2
  59. package/es/binding/CancelIconButton.js +0 -15
  60. package/es/binding/DataEditToolbar.d.ts +0 -13
  61. package/es/binding/DataEditToolbar.js +0 -28
  62. package/es/binding/DataObjectSelect.d.ts +0 -50
  63. package/es/binding/DataObjectSelect.js +0 -26
  64. package/es/binding/DeleteButton.d.ts +0 -8
  65. package/es/binding/DeleteButton.js +0 -14
  66. package/es/binding/DeleteIconButton.d.ts +0 -10
  67. package/es/binding/DeleteIconButton.js +0 -15
  68. package/es/binding/RefreshButton.d.ts +0 -3
  69. package/es/binding/RefreshButton.js +0 -14
  70. package/es/binding/RefreshIconButton.d.ts +0 -2
  71. package/es/binding/RefreshIconButton.js +0 -16
  72. package/es/binding/RefreshRowIconButton.d.ts +0 -7
  73. package/es/binding/RefreshRowIconButton.js +0 -15
  74. package/es/binding/SaveButton.d.ts +0 -3
  75. package/es/binding/SaveButton.js +0 -14
  76. package/es/binding/SaveIconButton.d.ts +0 -2
  77. package/es/binding/SaveIconButton.js +0 -15
  78. package/es/binding/index.d.ts +0 -19
  79. package/es/binding/index.js +0 -19
  80. package/es/index.d.ts +0 -3
  81. package/es/index.js +0 -3
  82. package/es/layout/AppLayoutDesktop.css +0 -65
  83. package/es/layout/AppLayoutDesktop.d.ts +0 -3
  84. package/es/layout/AppLayoutDesktop.js +0 -19
  85. package/es/layout/AppLayoutMobile.css +0 -75
  86. package/es/layout/AppLayoutMobile.d.ts +0 -3
  87. package/es/layout/AppLayoutMobile.js +0 -18
  88. package/es/layout/AppMenu.css +0 -67
  89. package/es/layout/AppMenu.d.ts +0 -8
  90. package/es/layout/AppMenu.js +0 -36
  91. package/es/layout/AppMenuItem.css +0 -97
  92. package/es/layout/AppMenuItem.d.ts +0 -50
  93. package/es/layout/AppMenuItem.js +0 -14
  94. package/es/layout/AppMenuSubheader.css +0 -18
  95. package/es/layout/AppMenuSubheader.d.ts +0 -4
  96. package/es/layout/AppMenuSubheader.js +0 -6
  97. package/es/layout/ErrorBoundary.css +0 -101
  98. package/es/layout/ErrorBoundary.d.ts +0 -30
  99. package/es/layout/ErrorBoundary.js +0 -81
  100. package/es/layout/PageContainer.css +0 -29
  101. package/es/layout/PageContainer.d.ts +0 -7
  102. package/es/layout/PageContainer.js +0 -6
  103. package/es/layout/PartnerToggle.d.ts +0 -5
  104. package/es/layout/PartnerToggle.js +0 -9
  105. package/es/layout/constants.d.ts +0 -2
  106. package/es/layout/constants.js +0 -2
  107. package/es/layout/index.css +0 -65
  108. package/es/layout/index.d.ts +0 -33
  109. package/es/layout/index.js +0 -31
  110. package/tsconfig.build.tsbuildinfo +0 -1
@@ -1,59 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import "./Lookup.css";
3
- import { Button, Textfield } from "@digdir/designsystemet-react";
4
- import ClearIcon from "@mui/icons-material/Close";
5
- import SearchIcon from "@mui/icons-material/Search";
6
- import { getLocalizedString } from "@olenbetong/appframe-core";
7
- import { useLookupState } from "@olenbetong/appframe-react";
8
- import clsx from "clsx";
9
- import { useRef } from "react";
10
- import { createPortal } from "react-dom";
11
- import { Combobox } from "./Combobox.js";
12
- export function useLookup({ getAnchorElement, slotProps, ...props }) {
13
- let { open, openDialog, onKeyDown, dialogRef, anchorName, inputId } = useLookupState({
14
- getAnchorElement,
15
- scrollParentSelector: "[data-virtualized-scroller]",
16
- });
17
- let initialSearchValueRef = useRef(undefined);
18
- function handleChange(item) {
19
- props.onChange?.(item);
20
- dialogRef.current?.close();
21
- }
22
- function handleOpenDialog(searchValue) {
23
- initialSearchValueRef.current = searchValue;
24
- openDialog();
25
- }
26
- return {
27
- open,
28
- openDialog: handleOpenDialog,
29
- onKeyDown,
30
- onChange: handleChange,
31
- dialogRef,
32
- anchorName,
33
- inputId,
34
- dialog: createPortal(_jsx("dialog", { ref: dialogRef, className: clsx("ObLookup-dialog", slotProps?.dialog?.className), onKeyDown: (evt) => evt.stopPropagation(), style: { positionAnchor: anchorName, ...slotProps?.dialog?.style }, children: open && (_jsx(Combobox, { ...props, initialSearchValue: initialSearchValueRef.current, onClose: () => dialogRef.current?.close(), onChange: handleChange })) }), document.body, inputId),
35
- };
36
- }
37
- export function AfLookup({ fullWidth = false, label, slotProps, value, ...props }) {
38
- let { inputId, open: _open, dialog, anchorName, openDialog, onKeyDown } = useLookup(props);
39
- let hasClear = !!(props.nullable && value && props.onChange);
40
- function handleInputKeyDown(event) {
41
- let hasModifier = event.ctrlKey || event.altKey || event.metaKey;
42
- let isTypeaheadKey = event.key.length === 1 && !hasModifier && !event.nativeEvent.isComposing;
43
- if (isTypeaheadKey) {
44
- event.preventDefault();
45
- event.stopPropagation();
46
- openDialog(event.key);
47
- return;
48
- }
49
- onKeyDown(event);
50
- }
51
- return (_jsxs("div", { style: { anchorName }, children: [_jsxs("div", { className: "ObLookup-inputWrap", style: {
52
- display: fullWidth ? "block" : "inline-block",
53
- "--ObLookup-buttons-width": hasClear ? "5.5rem" : "3rem",
54
- }, children: [_jsx(Textfield, { id: inputId, value: value ?? "", label: label, onClick: () => openDialog(), onKeyDown: handleInputKeyDown, className: clsx(slotProps?.textField?.className, "ObLookup-input"), ...slotProps?.textField, style: { width: fullWidth ? "100%" : undefined, ...slotProps?.textField?.style } }), _jsxs("div", { className: "ObLookup-buttons", children: [hasClear && (_jsx(Button, { icon: true, variant: "tertiary", "data-size": "sm", "aria-label": getLocalizedString("Clear"), onKeyDown: (evt) => evt.stopPropagation(), onClick: (evt) => {
55
- evt.stopPropagation();
56
- props.onChange?.(null);
57
- document.getElementById(inputId)?.focus();
58
- }, children: _jsx(ClearIcon, {}) })), _jsx(Button, { icon: true, variant: "tertiary", "data-size": "sm", "aria-label": getLocalizedString("Search"), onClick: () => openDialog(), children: _jsx(SearchIcon, {}) })] })] }), dialog] }));
59
- }
@@ -1,21 +0,0 @@
1
- import "./Lookup.css";
2
- import { type TextfieldProps } from "@digdir/designsystemet-react";
3
- import type { DistributiveOmit } from "@olenbetong/appframe-react";
4
- import type React from "react";
5
- import type { ComboboxProps } from "./Combobox.js";
6
- export type AfLookupEditProps<T extends Record<string, unknown>> = DistributiveOmit<ComboboxProps<T>, "value" | "onChange"> & {
7
- /**
8
- * Allows the user to enter a value manually that might not be in the list.
9
- */
10
- editable?: boolean;
11
- fullWidth?: boolean;
12
- label?: string;
13
- value?: string | null;
14
- lookupField: keyof T;
15
- onChange?: (evt: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
16
- slotProps?: {
17
- dialog?: Partial<React.HTMLProps<HTMLDialogElement>>;
18
- textField?: Partial<TextfieldProps>;
19
- };
20
- };
21
- export declare function AfLookupEdit<T extends Record<string, unknown>>({ fullWidth, label, onChange, slotProps, nullable, lookupField, value, ...props }: AfLookupEditProps<T>): React.JSX.Element;
@@ -1,49 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import "./Lookup.css";
3
- import { Button, Textfield } from "@digdir/designsystemet-react";
4
- import ClearIcon from "@mui/icons-material/Close";
5
- import SearchIcon from "@mui/icons-material/Search";
6
- import { getLocalizedString } from "@olenbetong/appframe-core";
7
- import clsx from "clsx";
8
- import { useLookup } from "./Lookup.js";
9
- export function AfLookupEdit({ fullWidth = false, label, onChange, slotProps, nullable, lookupField, value, ...props }) {
10
- let { inputId, dialog, anchorName, openDialog, onKeyDown } = useLookup({
11
- ...props,
12
- nullable,
13
- slotProps: { dialog: slotProps?.dialog },
14
- onChange: (item) => applyValue(item),
15
- });
16
- // The popup selects a single value from the dataset: the item's lookupField
17
- // is written to the input through the native value setter so the same
18
- // change event fires whether the user types or picks from the list/grid.
19
- function applyValue(item) {
20
- let input = document.getElementById(inputId);
21
- let nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value")?.set;
22
- if (input && nativeInputValueSetter) {
23
- nativeInputValueSetter.call(input, item ? String(item[lookupField]) : "");
24
- input.dispatchEvent(new Event("input", { bubbles: true }));
25
- }
26
- }
27
- function handleKeyDown(event) {
28
- if (event.key === "Enter") {
29
- event.preventDefault();
30
- event.stopPropagation();
31
- openDialog();
32
- }
33
- else {
34
- onKeyDown(event);
35
- }
36
- }
37
- let hasClear = !!(nullable && value && onChange);
38
- return (_jsxs("div", { style: { anchorName }, children: [_jsxs("div", { className: "ObLookup-inputWrap", style: {
39
- display: fullWidth ? "block" : "inline-block",
40
- "--ObLookup-buttons-width": hasClear ? "5.5rem" : "3rem",
41
- }, children: [_jsx(Textfield, { id: inputId, value: value ?? "", label: label, onChange: onChange, onKeyDown: handleKeyDown, className: clsx(slotProps?.textField?.className, "ObLookup-input"), ...slotProps?.textField, style: { width: fullWidth ? "100%" : undefined, ...slotProps?.textField?.style } }), _jsxs("div", { className: "ObLookup-buttons", children: [hasClear && (_jsx(Button, { icon: true, variant: "tertiary", "data-size": "sm", "aria-label": getLocalizedString("Clear"), onKeyDown: (evt) => evt.stopPropagation(), onClick: (evt) => {
42
- evt.stopPropagation();
43
- applyValue(null);
44
- document.getElementById(inputId)?.focus();
45
- }, children: _jsx(ClearIcon, {}) })), _jsx(Button, { icon: true, variant: "tertiary", "data-size": "sm", "aria-label": getLocalizedString("Search"), onClick: (evt) => {
46
- evt.stopPropagation();
47
- openDialog();
48
- }, children: _jsx(SearchIcon, {}) })] })] }), dialog] }));
49
- }
@@ -1,57 +0,0 @@
1
- .ObLookupGrid-root {
2
- height: 100%;
3
- overflow: hidden;
4
- overscroll-behavior: contain;
5
- border: 1px solid rgb(0 0 0 / 0.06);
6
- }
7
-
8
- .ObLookupGrid-header {
9
- display: grid;
10
- height: 40px;
11
- align-items: center;
12
- border-bottom: 1px solid rgb(0 0 0 / 0.12);
13
- background-color: rgb(0 0 0 / 0.03);
14
- font-weight: 600;
15
- }
16
-
17
- .ObLookupGrid-headerCell {
18
- padding: 0 8px;
19
- overflow: hidden;
20
- text-overflow: ellipsis;
21
- white-space: nowrap;
22
- }
23
-
24
- .ObLookupGrid-row {
25
- --active-color: oklch(from var(--brand-secondary, #999) l c h / 50%);
26
- display: grid;
27
- align-items: center;
28
- cursor: pointer;
29
- border-bottom: 1px solid rgb(0 0 0 / 0.06);
30
-
31
- &.active {
32
- background-color: var(--active-color);
33
- }
34
-
35
- &:hover {
36
- background-color: rgb(0 0 0 / 0.06);
37
- }
38
-
39
- &.active:hover {
40
- background-color: oklch(from var(--active-color) calc(l + 0.1) calc(c - 0.04) h);
41
- }
42
- }
43
-
44
- .ObLookupGrid-cell {
45
- padding: 0 8px;
46
- height: 100%;
47
- display: flex;
48
- align-items: center;
49
- overflow: hidden;
50
- text-overflow: ellipsis;
51
- white-space: nowrap;
52
-
53
- &.active {
54
- outline: 2px solid oklch(from var(--brand-secondary, #666) calc(l - 0.2) c h);
55
- outline-offset: -2px;
56
- }
57
- }
@@ -1,13 +0,0 @@
1
- import "./LookupGrid.css";
2
- import type { LookupColumn } from "@olenbetong/appframe-react";
3
- export interface LookupGridProps<T extends Record<string, unknown>> {
4
- columns: LookupColumn<T>[];
5
- data: T[];
6
- height: number;
7
- currentIndex: number;
8
- currentColumn: number;
9
- getItemId: (item: T | undefined) => string | undefined;
10
- isItemSelected?: (item: T) => boolean;
11
- onSelectItem: (item: T) => void;
12
- }
13
- export declare function LookupGrid<T extends Record<string, unknown>>({ columns, data, height, currentIndex, currentColumn, getItemId, isItemSelected, onSelectItem, }: LookupGridProps<T>): import("react").JSX.Element;
@@ -1,27 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import "./LookupGrid.css";
3
- import { getLocalizedString } from "@olenbetong/appframe-core";
4
- import clsx from "clsx";
5
- import { useEffect, useMemo, useRef } from "react";
6
- import { FixedSizeList as VirtualList } from "react-window";
7
- const ROW_HEIGHT = 40;
8
- const HEADER_HEIGHT = 40;
9
- function getColumnWidth(column) {
10
- if (typeof column.width === "number") {
11
- return `${column.width}px`;
12
- }
13
- return column.width ?? "minmax(80px, 1fr)";
14
- }
15
- export function LookupGrid({ columns, data, height, currentIndex, currentColumn, getItemId, isItemSelected, onSelectItem, }) {
16
- let listRef = useRef(null);
17
- let gridTemplateColumns = useMemo(() => columns.map(getColumnWidth).join(" "), [columns]);
18
- useEffect(() => listRef.current?.scrollToItem(currentIndex, "smart"), [currentIndex]);
19
- // oxlint-disable-next-line react/no-nested-component-definitions -- react-window row renderer
20
- let Row = ({ index, style }) => {
21
- let item = data[index];
22
- let itemId = getItemId(item);
23
- let active = index === currentIndex;
24
- return (_jsx("div", { role: "row", "aria-selected": active, className: clsx("ObLookupGrid-row", active && "active", isItemSelected?.(item) && "selected"), style: { ...style, gridTemplateColumns }, onClick: () => onSelectItem(item), id: itemId, children: columns.map((column, columnIndex) => (_jsx("div", { role: "gridcell", className: clsx("ObLookupGrid-cell", active && columnIndex === currentColumn && "active"), title: String(item[column.field] ?? ""), children: column.renderCell ? column.renderCell(item[column.field], item) : String(item[column.field] ?? "") }, column.field))) }, itemId));
25
- };
26
- return (_jsxs("div", { role: "grid", "aria-label": getLocalizedString("Search results"), className: "ObLookupGrid-root", children: [_jsx("div", { role: "row", className: "ObLookupGrid-header", style: { gridTemplateColumns }, children: columns.map((column) => (_jsx("div", { role: "columnheader", className: "ObLookupGrid-headerCell", children: column.headerName ?? column.field }, column.field))) }), _jsx(VirtualList, { ref: listRef, height: Math.max(0, height - HEADER_HEIGHT), width: "100%", itemCount: data.length, itemSize: ROW_HEIGHT, overscanCount: 5, children: Row })] }));
27
- }
@@ -1,5 +0,0 @@
1
- export * from "./BoundLookup.js";
2
- export * from "./Combobox.js";
3
- export * from "./Lookup.js";
4
- export * from "./LookupEdit.js";
5
- export * from "./LookupGrid.js";
@@ -1,5 +0,0 @@
1
- export * from "./BoundLookup.js";
2
- export * from "./Combobox.js";
3
- export * from "./Lookup.js";
4
- export * from "./LookupEdit.js";
5
- export * from "./LookupGrid.js";
@@ -1,9 +0,0 @@
1
- import { type CheckboxProps } from "@digdir/designsystemet-react";
2
- export type BoundCheckboxProps = Omit<CheckboxProps, "onChange" | "onKeyDown"> & {
3
- field: string;
4
- onChange?: (evt: React.ChangeEvent<HTMLInputElement>) => void;
5
- };
6
- export declare const BoundCheckbox: import("react").ForwardRefExoticComponent<Omit<CheckboxProps, "onChange" | "onKeyDown"> & {
7
- field: string;
8
- onChange?: (evt: React.ChangeEvent<HTMLInputElement>) => void;
9
- } & import("react").RefAttributes<HTMLInputElement>>;
@@ -1,13 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { Checkbox } from "@digdir/designsystemet-react";
3
- import { useField } from "@olenbetong/appframe-react";
4
- import { forwardRef } from "react";
5
- export const BoundCheckbox = forwardRef(function BoundCheckbox({ field, onChange: onChangeProp, checked: _checked, ...props }, ref) {
6
- let { value, setValue, onKeyDown } = useField(field);
7
- return (_jsx(Checkbox, { checked: value ?? false, onChange: (evt) => {
8
- onChangeProp?.(evt);
9
- if (!evt.defaultPrevented) {
10
- setValue(evt.target.checked);
11
- }
12
- }, onKeyDown: (evt) => onKeyDown(evt), ref: ref, name: field, ...props }));
13
- });
@@ -1,7 +0,0 @@
1
- import { type TextfieldProps } from "@digdir/designsystemet-react";
2
- export type BoundDatePickerProps = Omit<TextfieldProps, "value" | "onChange" | "onKeyDown" | "type"> & {
3
- field: string;
4
- };
5
- export declare const BoundDatePicker: import("react").ForwardRefExoticComponent<Omit<TextfieldProps, "onChange" | "onKeyDown" | "type" | "value"> & {
6
- field: string;
7
- } & import("react").RefAttributes<HTMLInputElement>>;
@@ -1,12 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { Textfield } from "@digdir/designsystemet-react";
3
- import { useField } from "@olenbetong/appframe-react";
4
- import { forwardRef } from "react";
5
- export const BoundDatePicker = forwardRef(function BoundDatePicker({ field, ...props }, ref) {
6
- let { error, value, onChange, onKeyDown } = useField(field);
7
- let inputValue = value;
8
- if (value instanceof Date) {
9
- inputValue = value.toISOString().split("T")[0];
10
- }
11
- return (_jsx(Textfield, { type: "date", name: field, error: error ?? undefined, ...props, value: inputValue ?? "", onChange: (evt) => onChange(evt), onKeyDown: (evt) => onKeyDown(evt), ref: ref }));
12
- });
@@ -1,7 +0,0 @@
1
- import { type TextfieldProps } from "@digdir/designsystemet-react";
2
- export type BoundDateTimePickerProps = Omit<TextfieldProps, "value" | "onChange" | "onKeyDown" | "type"> & {
3
- field: string;
4
- };
5
- export declare const BoundDateTimePicker: import("react").ForwardRefExoticComponent<Omit<TextfieldProps, "onChange" | "onKeyDown" | "type" | "value"> & {
6
- field: string;
7
- } & import("react").RefAttributes<HTMLInputElement>>;
@@ -1,14 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { Textfield } from "@digdir/designsystemet-react";
3
- import { useField } from "@olenbetong/appframe-react";
4
- import { forwardRef } from "react";
5
- export const BoundDateTimePicker = forwardRef(function BoundDateTimePicker({ field, ...props }, ref) {
6
- let { error, value, onChange, onKeyDown } = useField(field);
7
- let inputValue = value;
8
- if (value instanceof Date) {
9
- inputValue = value.toISOString().replace("Z", "");
10
- }
11
- return (_jsx(Textfield, { type: "datetime-local", name: field, error: error ?? undefined, ...props, value: inputValue ?? "", onChange: (evt) => {
12
- onChange(evt, evt.target.value ? `${evt.target.value}Z` : null);
13
- }, onKeyDown: (evt) => onKeyDown(evt), ref: ref }));
14
- });
@@ -1,6 +0,0 @@
1
- import { type InputProps } from "@digdir/designsystemet-react";
2
- export type BoundInputProps = Omit<InputProps, "onChange" | "onKeyDown" | "onBlur"> & {
3
- field: string;
4
- onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
5
- };
6
- export declare function BoundInput({ field, onChange: onChangeProp, ...props }: BoundInputProps): import("react").JSX.Element;
@@ -1,12 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { Input } from "@digdir/designsystemet-react";
3
- import { useField } from "@olenbetong/appframe-react";
4
- export function BoundInput({ field, onChange: onChangeProp, ...props }) {
5
- let { value, onChange, onKeyDown } = useField(field);
6
- return (_jsx(Input, { name: field, ...props, value: value ?? "", onChange: (event) => {
7
- onChangeProp?.(event);
8
- if (!event.defaultPrevented) {
9
- onChange(event);
10
- }
11
- }, onKeyDown: (evt) => onKeyDown(evt) }));
12
- }
@@ -1,20 +0,0 @@
1
- import { type TextfieldProps } from "@digdir/designsystemet-react";
2
- /**
3
- * A Designsystemet `Textfield` bound to an Appframe data source field via `useField`.
4
- *
5
- * Adds client-side numeric validation: rejects non-numeric characters and enforces
6
- * optional `precision` (total digits) and `scale` (decimal places) constraints.
7
- * Validation errors are reported to the parent via the `onError` callback so the
8
- * parent can track whether any field is in an error state (e.g., to disable Save).
9
- *
10
- * On blur the displayed value is normalized to a JS `Number` (comma decimal separators
11
- * are converted to dots) so the data source always stores a proper numeric value.
12
- */
13
- export type BoundNumericTextFieldProps = Omit<TextfieldProps, "onChange" | "onKeyDown" | "onError"> & {
14
- field: string;
15
- precision?: number;
16
- scale?: number;
17
- onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
18
- onError?: (error: string | null) => void;
19
- };
20
- export declare function BoundNumericTextField({ field, precision, scale, onChange: onChangeProp, onError, ...props }: BoundNumericTextFieldProps): import("react").JSX.Element;
@@ -1,58 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { Textfield } from "@digdir/designsystemet-react";
3
- import { getLocalizedString, localize } from "@olenbetong/appframe-core";
4
- import { useField } from "@olenbetong/appframe-react";
5
- import { useEffect, useState } from "react";
6
- export function BoundNumericTextField({ field, precision, scale, onChange: onChangeProp, onError, ...props }) {
7
- let { value, setValue, onChange, onKeyDown } = useField(field);
8
- let [error, setError] = useState(null);
9
- function checkNumber(value, precision, scale) {
10
- if (value[0] === "0") {
11
- value = value[0].replace("0", "");
12
- }
13
- let [integer, decimal] = value.split(",");
14
- if (value.includes(".")) {
15
- [integer, decimal] = value.split(".");
16
- }
17
- integer = integer.replace("-", "");
18
- if (integer.length > precision - scale) {
19
- setError(localize `The amount of whole numbers is too high. Allowed limit is ${precision - scale}`);
20
- return;
21
- }
22
- if (decimal && decimal.length > scale) {
23
- setError(localize `The amount of decimal places is too high. Allowed limit is ${scale}`);
24
- return;
25
- }
26
- setError(null);
27
- }
28
- function checkError(value, precision, scale) {
29
- let regExp = /[a-zA-Z `!@#$%^&*()_+=[\]{};':"\\|<>/?~]/;
30
- if (regExp.test(value)) {
31
- setError(getLocalizedString("Please enter a valid number"));
32
- }
33
- else if (value.substring(1).includes("-")) {
34
- setError(getLocalizedString("Please enter a valid number"));
35
- }
36
- else if (precision !== undefined && scale !== undefined) {
37
- checkNumber(value, precision, scale);
38
- }
39
- else {
40
- setError(null);
41
- }
42
- }
43
- useEffect(() => {
44
- onError?.(error);
45
- }, [error, onError]);
46
- return (_jsx(Textfield, { name: field, error: error ?? undefined, ...props, value: value ?? "", onChange: (event) => {
47
- onChangeProp?.(event);
48
- if (!event.defaultPrevented) {
49
- checkError(event.target.value, precision, scale);
50
- onChange(event);
51
- }
52
- }, onKeyDown: (evt) => onKeyDown(evt), onBlur: (evt) => {
53
- const raw = evt.target.value;
54
- if (raw !== "") {
55
- setValue(Number(raw.replaceAll(",", ".")));
56
- }
57
- } }));
58
- }
@@ -1,9 +0,0 @@
1
- import { type SelectProps } from "@digdir/designsystemet-react";
2
- export type BoundSelectProps = Omit<SelectProps, "onChange" | "value"> & {
3
- field: string;
4
- onChange?: (event: React.ChangeEvent<HTMLSelectElement>) => void;
5
- };
6
- export declare const BoundSelect: import("react").ForwardRefExoticComponent<Omit<SelectProps, "onChange" | "value"> & {
7
- field: string;
8
- onChange?: (event: React.ChangeEvent<HTMLSelectElement>) => void;
9
- } & import("react").RefAttributes<HTMLSelectElement>>;
@@ -1,13 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { Select } from "@digdir/designsystemet-react";
3
- import { useField } from "@olenbetong/appframe-react";
4
- import { forwardRef } from "react";
5
- export const BoundSelect = forwardRef(function BoundSelect({ field, onChange: onChangeProp, ...props }, ref) {
6
- let { value, onChange, onKeyDown } = useField(field);
7
- return (_jsx(Select, { name: field, value: value ?? "", onChange: (evt) => {
8
- onChangeProp?.(evt);
9
- if (!evt.defaultPrevented) {
10
- onChange(evt);
11
- }
12
- }, onKeyDown: (evt) => onKeyDown(evt), ...props, ref: ref }));
13
- });
@@ -1,9 +0,0 @@
1
- import { type SwitchProps } from "@digdir/designsystemet-react";
2
- export type BoundSwitchProps = Omit<SwitchProps, "onChange" | "checked"> & {
3
- field: string;
4
- onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
5
- };
6
- export declare const BoundSwitch: import("react").ForwardRefExoticComponent<Omit<SwitchProps, "checked" | "onChange"> & {
7
- field: string;
8
- onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
9
- } & import("react").RefAttributes<HTMLInputElement>>;
@@ -1,13 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { Switch } from "@digdir/designsystemet-react";
3
- import { useField } from "@olenbetong/appframe-react";
4
- import { forwardRef } from "react";
5
- export const BoundSwitch = forwardRef(function BoundSwitch({ field, onChange: onChangeProp, ...props }, ref) {
6
- let { value, setValue } = useField(field);
7
- return (_jsx(Switch, { name: field, ...props, checked: value ?? false, onChange: (evt) => {
8
- onChangeProp?.(evt);
9
- if (!evt.defaultPrevented) {
10
- setValue(evt.target.checked);
11
- }
12
- }, ref: ref }));
13
- });
@@ -1,7 +0,0 @@
1
- import { type TextfieldProps } from "@digdir/designsystemet-react";
2
- export type BoundTextFieldProps = Omit<TextfieldProps, "value" | "onChange" | "onKeyDown"> & {
3
- field: string;
4
- };
5
- export declare const BoundTextField: import("react").ForwardRefExoticComponent<Omit<TextfieldProps, "onChange" | "onKeyDown" | "value"> & {
6
- field: string;
7
- } & import("react").RefAttributes<HTMLInputElement & HTMLTextAreaElement>>;
@@ -1,22 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { Textfield } from "@digdir/designsystemet-react";
3
- import { useField } from "@olenbetong/appframe-react";
4
- import { forwardRef } from "react";
5
- export const BoundTextField = forwardRef(function BoundTextField({ field, ...props }, ref) {
6
- let { error, value, onChange, onKeyDown } = useField(field);
7
- let inputValue = value;
8
- if (props.type === "date" && value instanceof Date) {
9
- inputValue = value.toISOString().split("T")[0];
10
- }
11
- else if (["datetime", "datetime-local"].includes(props.type ?? "") && value instanceof Date) {
12
- inputValue = value.toISOString().replace("Z", "");
13
- }
14
- return (_jsx(Textfield, { name: field, error: error ?? undefined, ...props, value: inputValue ?? "", onChange: (evt) => {
15
- if (["datetime", "datetime-local"].includes(props.type ?? "")) {
16
- onChange(evt, evt.target.value ? `${evt.target.value}Z` : null);
17
- }
18
- else {
19
- onChange(evt);
20
- }
21
- }, onKeyDown: (evt) => onKeyDown(evt), ref: ref }));
22
- });
@@ -1,3 +0,0 @@
1
- import { type ButtonProps } from "@digdir/designsystemet-react";
2
- import { type ForwardRefExoticComponent, type RefAttributes } from "react";
3
- export declare const CancelButton: ForwardRefExoticComponent<ButtonProps & RefAttributes<HTMLButtonElement>>;
@@ -1,14 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { Button } from "@digdir/designsystemet-react";
3
- import { getLocalizedString } from "@olenbetong/appframe-core";
4
- import { useCancelButton } from "@olenbetong/appframe-react";
5
- import { forwardRef } from "react";
6
- export const CancelButton = forwardRef(function CancelButton({ onClick, children, ...props }, ref) {
7
- let { cancelEdit } = useCancelButton();
8
- return (_jsx(Button, { onClick: (evt) => {
9
- onClick?.(evt);
10
- if (!evt.defaultPrevented) {
11
- cancelEdit();
12
- }
13
- }, variant: "secondary", ...props, ref: ref, children: children ?? getLocalizedString("Cancel") }));
14
- });
@@ -1,2 +0,0 @@
1
- import { type ButtonProps } from "@digdir/designsystemet-react";
2
- export declare const CancelIconButton: import("react").ForwardRefExoticComponent<Omit<ButtonProps, "icon"> & import("react").RefAttributes<HTMLButtonElement>>;
@@ -1,15 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { Button } from "@digdir/designsystemet-react";
3
- import UndoIcon from "@mui/icons-material/Undo";
4
- import { getLocalizedString } from "@olenbetong/appframe-core";
5
- import { useCancelButton } from "@olenbetong/appframe-react";
6
- import { forwardRef } from "react";
7
- export const CancelIconButton = forwardRef(function CancelIconButton({ onClick, children, ...props }, ref) {
8
- let { cancelEdit } = useCancelButton();
9
- return (_jsx(Button, { icon: true, "aria-label": getLocalizedString("Revert unsaved changes"), variant: "tertiary", onClick: (evt) => {
10
- onClick?.(evt);
11
- if (!evt.defaultPrevented) {
12
- cancelEdit();
13
- }
14
- }, ...props, ref: ref, children: children ?? _jsx(UndoIcon, {}) }));
15
- });
@@ -1,13 +0,0 @@
1
- import type { DataObject } from "@olenbetong/appframe-data";
2
- export type DataEditToolbarProps = React.HTMLAttributes<HTMLDivElement> & {
3
- /**
4
- * If different data objects are used for navigation and editing, you can set the data object
5
- * used for navigation with this property.
6
- */
7
- navigationDataObject?: DataObject<any>;
8
- /**
9
- * If true, will add buttons to move to the next/previous index in the data object.
10
- */
11
- showNavigation?: boolean;
12
- };
13
- export declare function DataEditToolbar({ children, navigationDataObject, showNavigation, style, ...props }: DataEditToolbarProps): import("react").JSX.Element;
@@ -1,28 +0,0 @@
1
- import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Button, Tooltip } from "@digdir/designsystemet-react";
3
- import ChevronLeftIcon from "@mui/icons-material/ChevronLeft";
4
- import ChevronRightIcon from "@mui/icons-material/ChevronRight";
5
- import { getLocalizedString } from "@olenbetong/appframe-core";
6
- import { useCurrentIndex, useDataLength, useDataObject } from "@olenbetong/appframe-react";
7
- import { CancelIconButton } from "./CancelIconButton.js";
8
- import { RefreshRowIconButton } from "./RefreshRowIconButton.js";
9
- import { SaveIconButton } from "./SaveIconButton.js";
10
- function IndexNavigator({ dataObject }) {
11
- let count = useDataLength(dataObject);
12
- let index = useCurrentIndex(dataObject);
13
- if (count <= 1) {
14
- return null;
15
- }
16
- return (_jsxs(_Fragment, { children: [_jsx(Button, { icon: true, variant: "tertiary", "aria-label": getLocalizedString("Previous"), onClick: () => dataObject.setCurrentIndex(index - 1), disabled: index <= 0, children: _jsx(ChevronLeftIcon, {}) }), _jsx(Button, { icon: true, variant: "tertiary", "aria-label": getLocalizedString("Next"), onClick: () => dataObject.setCurrentIndex(index + 1), disabled: index >= count - 1, children: _jsx(ChevronRightIcon, {}) })] }));
17
- }
18
- export function DataEditToolbar({ children, navigationDataObject, showNavigation, style, ...props }) {
19
- let dataObject = useDataObject();
20
- return (_jsxs("div", { style: {
21
- display: "flex",
22
- alignItems: "center",
23
- minHeight: "48px",
24
- borderBottom: "1px solid rgb(0 0 0 / 0.12)",
25
- borderTop: "1px solid rgb(0 0 0 / 0.12)",
26
- ...style,
27
- }, ...props, children: [_jsx(Tooltip, { content: getLocalizedString("Save changes"), children: _jsx(SaveIconButton, {}) }), _jsx(Tooltip, { content: getLocalizedString("Revert unsaved changes"), children: _jsx(CancelIconButton, {}) }), _jsx(Tooltip, { content: getLocalizedString("Refresh record"), children: _jsx(RefreshRowIconButton, {}) }), children, showNavigation && (_jsx("div", { style: { marginLeft: "auto" }, children: _jsx(IndexNavigator, { dataObject: navigationDataObject ?? dataObject }) }))] }));
28
- }