@pinuts/bsr-uikit-relaunch 0.4.2 → 0.4.4

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 (51) hide show
  1. package/dist/hooks/withFieldGroup.d.ts.map +1 -1
  2. package/dist/hooks/withFieldGroup.js +46 -18
  3. package/dist/index.js +1 -1
  4. package/dist/items/AbholortMaterialienField/AbholortMaterialienField.d.ts.map +1 -1
  5. package/dist/items/AbholortMaterialienField/AbholortMaterialienField.js +7 -3
  6. package/dist/items/BSRAddressSelector/BSRAddressContext.d.ts +1 -0
  7. package/dist/items/BSRAddressSelector/BSRAddressContext.d.ts.map +1 -1
  8. package/dist/items/BSRAddressSelector/BSRAddressContext.js +4 -1
  9. package/dist/items/BSRAddressSelector/BSRAddressSelector.d.ts.map +1 -1
  10. package/dist/items/BSRAddressSelector/BSRAddressSelector.js +41 -2
  11. package/dist/items/BSRAddressSelector/BSRAutocompleteField.d.ts +9 -1
  12. package/dist/items/BSRAddressSelector/BSRAutocompleteField.d.ts.map +1 -1
  13. package/dist/items/BSRAddressSelector/BSRAutocompleteField.js +29 -7
  14. package/dist/items/BSRAddressSelector/BSRStreetPlzSelector.js +6 -1
  15. package/dist/items/BSRAddressSelector/HouseNumberSelectField.d.ts.map +1 -1
  16. package/dist/items/BSRAddressSelector/HouseNumberSelectField.js +7 -3
  17. package/dist/items/BSRAddressSelector/withAddressGroupValidation.d.ts +12 -0
  18. package/dist/items/BSRAddressSelector/withAddressGroupValidation.d.ts.map +1 -0
  19. package/dist/items/BSRAddressSelector/withAddressGroupValidation.js +57 -0
  20. package/dist/items/FieldsetWrapper/FieldsetWrapper.d.ts +1 -0
  21. package/dist/items/FieldsetWrapper/FieldsetWrapper.d.ts.map +1 -1
  22. package/dist/items/FieldsetWrapper/FieldsetWrapper.js +28 -0
  23. package/dist/items/FileUploadField/FileUploadField.d.ts.map +1 -1
  24. package/dist/items/FileUploadField/FileUploadField.js +19 -3
  25. package/dist/items/FileUploadField/uploadedFileStore.d.ts +1 -0
  26. package/dist/items/FileUploadField/uploadedFileStore.d.ts.map +1 -1
  27. package/dist/items/FileUploadField/uploadedFileStore.js +10 -1
  28. package/dist/items/Grid/BSRGridColumn.d.ts.map +1 -1
  29. package/dist/items/Grid/BSRGridColumn.js +15 -1
  30. package/dist/items/Grid/BSRGridRow.d.ts.map +1 -1
  31. package/dist/items/Grid/BSRGridRow.js +15 -1
  32. package/dist/items/ReviewValue/ReviewValueList.d.ts +1 -1
  33. package/dist/items/ReviewValue/ReviewValueList.d.ts.map +1 -1
  34. package/dist/items/ReviewValue/ReviewValueList.js +3 -3
  35. package/dist/locales.d.ts +2 -0
  36. package/dist/locales.js +2 -0
  37. package/dist/shared/ErrorMessagesInfoBox/ErrorMessagesInfoBox.d.ts.map +1 -1
  38. package/dist/shared/ErrorMessagesInfoBox/ErrorMessagesInfoBox.js +3 -1
  39. package/dist/shared/FormWidget/FormWidgetControlPage.d.ts.map +1 -1
  40. package/dist/shared/FormWidget/FormWidgetControlPage.js +14 -5
  41. package/dist/shared/FormWidget/ReviewLayoutContext.d.ts +11 -0
  42. package/dist/shared/FormWidget/ReviewLayoutContext.d.ts.map +1 -0
  43. package/dist/shared/FormWidget/ReviewLayoutContext.js +17 -0
  44. package/dist/shared/KehrenbuergerForm/KehrenbuergerForm.d.ts.map +1 -1
  45. package/dist/shared/KehrenbuergerForm/KehrenbuergerForm.js +29 -2
  46. package/dist/styles/_errorMessagesInfoBox.scss +2 -1
  47. package/dist/styles/_forcedColors.scss +159 -0
  48. package/dist/styles/_form.scss +109 -3
  49. package/dist/styles/_review.scss +52 -3
  50. package/dist/styles/main.scss +1 -0
  51. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"BSRGridRow.d.ts","sourceRoot":"","sources":["../../../src/items/Grid/BSRGridRow.jsx"],"names":[],"mappings":";AAKA;;;sBAUC;;;;;;;kBAfiB,OAAO;sBACH,YAAY"}
1
+ {"version":3,"file":"BSRGridRow.d.ts","sourceRoot":"","sources":["../../../src/items/Grid/BSRGridRow.jsx"],"names":[],"mappings":";AAMA;;;sBAqBC;;;;;;;kBA3BiC,OAAO;sBACnB,YAAY"}
@@ -4,15 +4,29 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
- var _react = _interopRequireDefault(require("react"));
7
+ var _react = _interopRequireWildcard(require("react"));
8
8
  var _propTypes = _interopRequireDefault(require("prop-types"));
9
9
  var _formBuilder = require("@pinuts/form-builder");
10
+ var _ReviewLayoutContext = _interopRequireDefault(require("../../shared/FormWidget/ReviewLayoutContext.js"));
10
11
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
13
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
11
14
  const BSRGridRow = _ref => {
12
15
  let {
13
16
  components,
14
17
  children
15
18
  } = _ref;
19
+ const {
20
+ active: isReviewLayout
21
+ } = (0, _react.useContext)(_ReviewLayoutContext.default);
22
+
23
+ // Kontrollseite: einspaltige Liste statt Formular-Raster
24
+ if (isReviewLayout) {
25
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, components && /*#__PURE__*/_react.default.createElement(_formBuilder.ComponentPopulator, {
26
+ components: components,
27
+ formId: ''
28
+ }), children);
29
+ }
16
30
  return /*#__PURE__*/_react.default.createElement("div", {
17
31
  className: 'row'
18
32
  }, components && /*#__PURE__*/_react.default.createElement(_formBuilder.ComponentPopulator, {
@@ -9,7 +9,7 @@ declare function ReviewValueList({ items }: {
9
9
  }): React.JSX.Element;
10
10
  declare namespace ReviewValueList {
11
11
  namespace propTypes {
12
- let items: PropTypes.Requireable<NonNullable<string | number>[]>;
12
+ let items: PropTypes.Requireable<NonNullable<string | number | PropTypes.ReactElementLike>[]>;
13
13
  }
14
14
  }
15
15
  import React from 'react';
@@ -1 +1 @@
1
- {"version":3,"file":"ReviewValueList.d.ts","sourceRoot":"","sources":["../../../src/items/ReviewValue/ReviewValueList.jsx"],"names":[],"mappings":";AAIA;;;;GAIG;AACH;;sBAgBC;;;;;;kBAzBiB,OAAO;sBACH,YAAY"}
1
+ {"version":3,"file":"ReviewValueList.d.ts","sourceRoot":"","sources":["../../../src/items/ReviewValue/ReviewValueList.jsx"],"names":[],"mappings":";AAIA;;;;GAIG;AACH;;sBAkBC;;;;;;kBA3BiB,OAAO;sBACH,YAAY"}
@@ -27,10 +27,10 @@ const ReviewValueList = _ref => {
27
27
  // Werte können sich wiederholen (gleiche Label-Texte), daher Index im Key
28
28
  // eslint-disable-next-line react/no-array-index-key
29
29
  _react.default.createElement("li", {
30
- key: `${index}-${item}`
31
- }, /*#__PURE__*/_react.default.createElement(_HTMLParserSanitized.HTMLParserSanitized, null, String(item)))));
30
+ key: `${index}-${/*#__PURE__*/_react.default.isValidElement(item) ? '' : item}`
31
+ }, /*#__PURE__*/_react.default.isValidElement(item) ? item : /*#__PURE__*/_react.default.createElement(_HTMLParserSanitized.HTMLParserSanitized, null, String(item)))));
32
32
  };
33
33
  ReviewValueList.propTypes = {
34
- items: _propTypes.default.arrayOf(_propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.number]))
34
+ items: _propTypes.default.arrayOf(_propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.number, _propTypes.default.element]))
35
35
  };
36
36
  var _default = exports.default = ReviewValueList;
package/dist/locales.d.ts CHANGED
@@ -84,6 +84,7 @@ export namespace resources {
84
84
  let addressNotFound: string;
85
85
  let loading: string;
86
86
  let checkAddress: string;
87
+ let checkAddressRequired: string;
87
88
  let street: string;
88
89
  let houseNumber: string;
89
90
  let resetBtn: string;
@@ -139,6 +140,7 @@ export namespace resources {
139
140
  let readyForUpload: string;
140
141
  let isUploading: string;
141
142
  let uploadSuccessful: string;
143
+ let openFileAria: string;
142
144
  namespace errors {
143
145
  let uploadFileTooLarge: string;
144
146
  let uploadFileTooLargeNoLimit: string;
package/dist/locales.js CHANGED
@@ -79,6 +79,7 @@ const resources = exports.resources = {
79
79
  'addressNotFound': 'Die Strasse und/oder Strasse-/ und Hausnummerkombination konnte nicht gefunden werden, bitte Suchen Sie erneut und wählen Sie eine Strasse aus der Autovervollständigung aus.',
80
80
  'loading': 'Adresse wird überprüft ...',
81
81
  'checkAddress': 'Adresse prüfen',
82
+ 'checkAddressRequired': 'Bitte die Adresse mit „{{button}}“ bestätigen.',
82
83
  'street': 'Straße',
83
84
  'houseNumber': 'Hausnummer',
84
85
  'resetBtn': 'X',
@@ -132,6 +133,7 @@ const resources = exports.resources = {
132
133
  readyForUpload: 'Bereit zum Hochladen: {{filename}}',
133
134
  isUploading: '{{filename}} wird hochgeladen ...',
134
135
  uploadSuccessful: '{{filename}} wurde hochgeladen.',
136
+ openFileAria: '{{label}} anzeigen (öffnet in neuem Tab)',
135
137
  errors: {
136
138
  // Fehlercodes des Servers
137
139
  uploadFileTooLarge: '{{filename}} ist zu groß. Erlaubt sind maximal {{maxSize}}.',
@@ -1 +1 @@
1
- {"version":3,"file":"ErrorMessagesInfoBox.d.ts","sourceRoot":"","sources":["../../../src/shared/ErrorMessagesInfoBox/ErrorMessagesInfoBox.jsx"],"names":[],"mappings":";AAgEA;;;;sBAmEC;;;;;;;;kBAnI8D,OAAO;sBAChD,YAAY"}
1
+ {"version":3,"file":"ErrorMessagesInfoBox.d.ts","sourceRoot":"","sources":["../../../src/shared/ErrorMessagesInfoBox/ErrorMessagesInfoBox.jsx"],"names":[],"mappings":";AAmEA;;;;sBAmEC;;;;;;;;kBAtI8D,OAAO;sBAChD,YAAY"}
@@ -17,7 +17,9 @@ const {
17
17
  } = _formBuilder.formik;
18
18
  const focusFieldByName = (formId, name) => {
19
19
  const form = formId ? document.getElementById(formId) : document;
20
- const field = form?.querySelector(`[name="${name}"]`);
20
+ // Gruppenfelder ohne eigenes Eingabefeld (BSRAddressSelector): das als ungültig markierte Unterfeld
21
+ const escapedName = CSS.escape(name);
22
+ const field = form?.querySelector(`[name="${escapedName}"]`) || form?.querySelector(`[name^="${escapedName}-"][aria-invalid="true"]`);
21
23
  if (field) {
22
24
  field.scrollIntoView({
23
25
  behavior: 'smooth',
@@ -1 +1 @@
1
- {"version":3,"file":"FormWidgetControlPage.d.ts","sourceRoot":"","sources":["../../../src/shared/FormWidget/FormWidgetControlPage.jsx"],"names":[],"mappings":";AASA;;;;;;;;sBAuDC;;;;;;;;;;;;;;;;;kBAhEwC,OAAO;sBAC1B,YAAY"}
1
+ {"version":3,"file":"FormWidgetControlPage.d.ts","sourceRoot":"","sources":["../../../src/shared/FormWidget/FormWidgetControlPage.jsx"],"names":[],"mappings":";AAWA;;;;;;;;sBA6DC;;;;;;;;;;;;;;;;;kBAxEwC,OAAO;sBAC1B,YAAY"}
@@ -10,10 +10,15 @@ var _formBuilder = require("@pinuts/form-builder");
10
10
  var _reactI18next = require("react-i18next");
11
11
  var _HTMLParserSanitized = require("../../items/HTMLParserSanitized/HTMLParserSanitized.jsx");
12
12
  var _Button = _interopRequireDefault(require("../../items/Button/Button.jsx"));
13
+ var _ReviewLayoutContext = _interopRequireDefault(require("./ReviewLayoutContext.js"));
13
14
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
14
15
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
15
16
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
16
17
  const noop = () => {};
18
+ const reviewLayout = {
19
+ active: true,
20
+ inList: false
21
+ };
17
22
  const FormWidgetControlPage = _ref => {
18
23
  let {
19
24
  captions,
@@ -36,14 +41,16 @@ const FormWidgetControlPage = _ref => {
36
41
  return /*#__PURE__*/_react.default.createElement("section", {
37
42
  className: "pi-review",
38
43
  "aria-labelledby": headingId
39
- }, /*#__PURE__*/_react.default.createElement("h1", {
44
+ }, /*#__PURE__*/_react.default.createElement("h2", {
40
45
  className: "pi-review-heading",
41
46
  id: headingId,
42
47
  tabIndex: -1,
43
48
  ref: headingRef
44
49
  }, t(captions.header)), captions.text && /*#__PURE__*/_react.default.createElement("div", {
45
50
  className: "info-text pi-review-infotext"
46
- }, /*#__PURE__*/_react.default.createElement(_HTMLParserSanitized.HTMLParserSanitized, null, t(captions.text))), /*#__PURE__*/_react.default.createElement(_formBuilder.FormBuilder, {
51
+ }, /*#__PURE__*/_react.default.createElement(_HTMLParserSanitized.HTMLParserSanitized, null, t(captions.text))), /*#__PURE__*/_react.default.createElement(_ReviewLayoutContext.default.Provider, {
52
+ value: reviewLayout
53
+ }, /*#__PURE__*/_react.default.createElement(_formBuilder.FormBuilder, {
47
54
  key: `${formId}-control`,
48
55
  formId: `${formId}-control`,
49
56
  formConfig: formConfig,
@@ -51,12 +58,14 @@ const FormWidgetControlPage = _ref => {
51
58
  initialValues: formValues,
52
59
  readOnly: true,
53
60
  flagsToInherit: ['reviewMode']
61
+ }, /*#__PURE__*/_react.default.createElement("div", {
62
+ className: "pi-review-actions"
54
63
  }, /*#__PURE__*/_react.default.createElement(_Button.default, {
55
- color: "white",
56
- className: "me-2",
64
+ color: "outline-brick",
57
65
  onClick: onBack,
58
66
  text: captions.backBtn
59
67
  }), /*#__PURE__*/_react.default.createElement(_Button.default, {
68
+ color: "brick",
60
69
  onClick: onSubmit,
61
70
  text: captions.submitBtn,
62
71
  ariaAttributes: {
@@ -65,7 +74,7 @@ const FormWidgetControlPage = _ref => {
65
74
  inputProps: {
66
75
  disabled: isSubmitting
67
76
  }
68
- })));
77
+ })))));
69
78
  };
70
79
  FormWidgetControlPage.propTypes = {
71
80
  captions: _propTypes.default.shape({
@@ -0,0 +1,11 @@
1
+ export default ReviewLayoutContext;
2
+ /**
3
+ * Layout der Kontrollseite (FormWidgetControlPage).
4
+ * active: Raster aus, Fieldsets werden zu Abschnitten mit Überschrift und einer Liste.
5
+ * inList: innerhalb eines Abschnitts-<dl>, Felder liefern nur ihr dt/dd-Paar.
6
+ */
7
+ declare const ReviewLayoutContext: import("react").Context<{
8
+ active: boolean;
9
+ inList: boolean;
10
+ }>;
11
+ //# sourceMappingURL=ReviewLayoutContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReviewLayoutContext.d.ts","sourceRoot":"","sources":["../../../src/shared/FormWidget/ReviewLayoutContext.js"],"names":[],"mappings":";AAEA;;;;GAIG;AACH;;;GAA4E"}
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _react = require("react");
8
+ /**
9
+ * Layout der Kontrollseite (FormWidgetControlPage).
10
+ * active: Raster aus, Fieldsets werden zu Abschnitten mit Überschrift und einer Liste.
11
+ * inList: innerhalb eines Abschnitts-<dl>, Felder liefern nur ihr dt/dd-Paar.
12
+ */
13
+ const ReviewLayoutContext = /*#__PURE__*/(0, _react.createContext)({
14
+ active: false,
15
+ inList: false
16
+ });
17
+ var _default = exports.default = ReviewLayoutContext;
@@ -1 +1 @@
1
- {"version":3,"file":"KehrenbuergerForm.d.ts","sourceRoot":"","sources":["../../../src/shared/KehrenbuergerForm/KehrenbuergerForm.jsx"],"names":[],"mappings":";AA6DA;;;;;;GAMG;AACH;;;;sBAgHC;;;;;;;;kBApL2D,OAAO;sBAC7C,YAAY"}
1
+ {"version":3,"file":"KehrenbuergerForm.d.ts","sourceRoot":"","sources":["../../../src/shared/KehrenbuergerForm/KehrenbuergerForm.jsx"],"names":[],"mappings":";AA6EA;;;;;;GAMG;AACH;;;;sBAmHC;;;;;;;;kBAvM2D,OAAO;sBAC7C,YAAY"}
@@ -51,6 +51,30 @@ const transformPayload = values => ({
51
51
  data: values
52
52
  });
53
53
 
54
+ // Der UM liefert die Upload-URL relativ ("/p/…"). Auf der Website zeigt /p nicht auf den UM,
55
+ // deshalb wie Config-Abruf und Absenden über restUrl leiten.
56
+ const RELATIVE_REST_PREFIX = '/p/';
57
+ const withUploadUrlsFromRestUrl = function () {
58
+ let components = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
59
+ let restUrl = arguments.length > 1 ? arguments[1] : undefined;
60
+ return components.map(component => {
61
+ const uploadUrl = component.config?.uploadUrl;
62
+ const config = typeof uploadUrl === 'string' && uploadUrl.startsWith(RELATIVE_REST_PREFIX) ? {
63
+ ...component.config,
64
+ uploadUrl: `${restUrl}/${uploadUrl.slice(RELATIVE_REST_PREFIX.length)}`
65
+ } : component.config;
66
+ return {
67
+ ...component,
68
+ ...(config && {
69
+ config
70
+ }),
71
+ ...(component.components && {
72
+ components: withUploadUrlsFromRestUrl(component.components, restUrl)
73
+ })
74
+ };
75
+ });
76
+ };
77
+
54
78
  // Bestätigungs-Link (Double-Opt-In): ?c=<aktionId> in der URL.
55
79
  // Prod nutzt normale URLs (?c=... vor dem #), die CMS-Vorschau Hash-URLs
56
80
  // (#/pfad?c=...) - deshalb beide Stellen prüfen.
@@ -106,7 +130,10 @@ const KehrenbuergerForm = _ref2 => {
106
130
  if (!formConfigs?.anmeldung) {
107
131
  throw new Error('In der Antwort fehlt data.formConfigs.anmeldung');
108
132
  }
109
- setFormConfig(formConfigs.anmeldung);
133
+ setFormConfig({
134
+ ...formConfigs.anmeldung,
135
+ components: withUploadUrlsFromRestUrl(formConfigs.anmeldung.components, restUrl)
136
+ });
110
137
  setRawCaptions(formConfigs.captions || {});
111
138
  }).catch(() => {
112
139
  if (!aborted) {
@@ -116,7 +143,7 @@ const KehrenbuergerForm = _ref2 => {
116
143
  return () => {
117
144
  aborted = true;
118
145
  };
119
- }, [configUrl]);
146
+ }, [configUrl, restUrl]);
120
147
 
121
148
  // DOI: Anmeldung per PUT bestätigen, sobald die Captions da sind
122
149
  const doiConfirmed = (0, _react.useRef)(false);
@@ -7,7 +7,8 @@
7
7
  .pi-message-text {
8
8
  display: flex;
9
9
  flex-direction: column;
10
- margin: 0 0 ($base-gap * 4);
10
+ // oben wie der Abstand des ersten Fieldsets (my-3), sonst klebt die Box am Einleitungstext
11
+ margin: ($base-gap * 4) 0;
11
12
  padding: ($base-gap * 3) ($base-gap * 5); // 12px 20px
12
13
  border: $bsr-border-width-l solid $error;
13
14
  border-radius: $border-radius;
@@ -0,0 +1,159 @@
1
+ @use "sass:math";
2
+
3
+ // =========================================================================
4
+ // FORCED COLORS / HIGH CONTRAST
5
+ // (Windows-Kontrastdesigns, Firefox "Website contrast: Custom")
6
+ //
7
+ // Der Browser erzwingt dann eigene Farben. Zwei Fehlerbilder:
8
+ // 1. Indikator als url()-SVG -> wird NICHT umgefaerbt, bleibt orange
9
+ // 2. Indikator als background-color -> wird auf Canvas geflacht, verschwindet
10
+ // Reine box-shadow-Fokusringe verschwinden ebenfalls.
11
+ //
12
+ // Loesung: Box mit forced-color-adjust: none aus der Automatik nehmen und mit
13
+ // System-Keywords neu zeichnen (CanvasText = "Text", Canvas = "Hintergrund",
14
+ // GrayText = deaktiviert, Highlight = Auswahl/Fokus).
15
+ //
16
+ // ZWEI FALLEN:
17
+ // - forced-color-adjust VERERBT. Nur auf die Indikator-Box setzen, nie auf
18
+ // label oder Wrapper - sonst faellt der Labeltext aus der Nutzerpalette.
19
+ // - Wer es setzt, besitzt ALLE Farben des Elements inkl. outline-color.
20
+ // Bestehende Fokusregeln muessen mit fc-focus-ring gespiegelt werden.
21
+ //
22
+ // KEIN nativer Fallback (appearance: auto): Firefox malt native Controls im
23
+ // HCM in seiner eigenen Schwarz/Weiss-Palette und ignoriert die Nutzerfarben.
24
+ // Die Mixins funktionieren auf echten <input> wie auf Pseudo-Elementen.
25
+ // =========================================================================
26
+
27
+ /// Einziger Ansatzpunkt fuer die Media Query.
28
+ @mixin forced-colors {
29
+ @media (forced-colors: active) {
30
+ @content;
31
+ }
32
+ }
33
+
34
+ @mixin fc-control-box($border: CanvasText, $surface: Canvas) {
35
+ forced-color-adjust: none;
36
+ border-color: $border;
37
+ background-color: $surface;
38
+ background-image: none;
39
+ box-shadow: none;
40
+ }
41
+
42
+ @mixin fc-control-box-disabled($border: GrayText, $surface: Canvas) {
43
+ @include fc-control-box($border, $surface);
44
+ }
45
+
46
+ /// Radio-Punkt als Gradient auf der Box selbst - kein zusaetzliches Element,
47
+ /// kein Positionierungskontext. Setzt fc-control-box voraus, sonst wuerde der
48
+ /// Gradient auf none gezwungen. background-origin macht die Geometrie
49
+ /// unabhaengig von der Border-Breite (1,4px normal / 2px bei Hover, Fehler).
50
+ /// $size in px fuer bekannte Boxgroessen, oder ein Prozentwert, wenn die Box
51
+ /// unbekannt ist (dann skaliert der Punkt mit - der Gradient liegt ueber der
52
+ /// ganzen Box, `circle at center` mit Prozent-Stops).
53
+ @mixin fc-indicator-radio($color: CanvasText, $size: 16px) {
54
+ @if unit($size) == "%" {
55
+ $radius: $size * 0.5;
56
+
57
+ background-image: radial-gradient(
58
+ circle at center,
59
+ #{$color} 0,
60
+ #{$color} #{$radius},
61
+ transparent #{$radius + 1%}
62
+ );
63
+ } @else {
64
+ $radius: $size * 0.5;
65
+
66
+ background-image: radial-gradient(
67
+ circle at center,
68
+ #{$color} 0,
69
+ #{$color} #{$radius - 0.5px},
70
+ transparent #{$radius}
71
+ );
72
+ }
73
+ background-repeat: no-repeat;
74
+ background-position: center;
75
+ background-origin: border-box;
76
+ }
77
+
78
+ /// Haken aus zwei beschnittenen Gradient-Baendern.
79
+ ///
80
+ /// Groesse und Position sind in Prozent der Box ausgedrueckt, der Haken passt
81
+ /// sich also JEDER Boxgroesse an - noetig, weil die vom UM gelieferten
82
+ /// Formulare unterschiedlich grosse Controls verwenden.
83
+ ///
84
+ /// Herleitung gegen die urspruengliche 24x24-Geometrie (kurzer Strich 8x8 bei
85
+ /// 3/10, langer 12x12 bei 9/6). background-position in Prozent bedeutet
86
+ /// Offset = p * (Box - Bild), daraus:
87
+ /// kurz: 8/24 = 33.333%, p_x = 3/(24-8) = 18.75%, p_y = 10/16 = 62.5%
88
+ /// lang: 12/24 = 50%, p_x = 9/(24-12) = 75%, p_y = 6/12 = 50%
89
+ /// Bei 24px ergibt das exakt die alten Pixelwerte.
90
+ ///
91
+ /// Die Strichstaerke bleibt bewusst in px, damit der Haken auch in grossen
92
+ /// Boxen nicht fett wird.
93
+ @mixin fc-indicator-check($color: CanvasText, $stroke: 3.2px) {
94
+ $half: $stroke * 0.5; // deckende Haelfte
95
+ $soft: $half + 0.4px; // weiche Kante gegen Treppchen auf den Diagonalen
96
+
97
+ background-image:
98
+ // kurzer Strich, oben links -> Scheitelpunkt ("\")
99
+ linear-gradient(
100
+ 45deg,
101
+ transparent calc(50% - #{$soft}),
102
+ #{$color} calc(50% - #{$half}),
103
+ #{$color} calc(50% + #{$half}),
104
+ transparent calc(50% + #{$soft})
105
+ ),
106
+ // langer Strich, Scheitelpunkt -> oben rechts ("/")
107
+ linear-gradient(
108
+ 135deg,
109
+ transparent calc(50% - #{$soft}),
110
+ #{$color} calc(50% - #{$half}),
111
+ #{$color} calc(50% + #{$half}),
112
+ transparent calc(50% + #{$soft})
113
+ );
114
+ background-size: 33.333% 33.333%, 50% 50%;
115
+ background-position: 18.75% 62.5%, 75% 50%;
116
+ background-repeat: no-repeat;
117
+ background-origin: border-box;
118
+ }
119
+
120
+ /// Pflicht auf jedem Element mit forced-color-adjust: none.
121
+ @mixin fc-focus-ring($color: Highlight) {
122
+ outline-color: $color;
123
+ box-shadow: none;
124
+ }
125
+
126
+ /// Wie fc-focus-ring, aber fuer Elemente ohne eigene outline-Deklaration
127
+ /// (Basiszustand setzt outline: none oder nutzt nur box-shadow).
128
+ @mixin fc-focus-ring-full($color: Highlight, $width: 2px, $offset: 2px) {
129
+ outline: $width solid $color;
130
+ outline-offset: $offset;
131
+ box-shadow: none;
132
+ }
133
+
134
+ // -------------------------------------------------------------------------
135
+ // KACHEL- / PILL-SELEKTOREN
136
+ // "Ausgewaehlt" allein ueber background-color wird auf Canvas geflacht und
137
+ // damit ununterscheidbar (WCAG 1.4.1). Systempaar dafuer: Highlight /
138
+ // HighlightText.
139
+ //
140
+ // Anders als bei fc-control-box vererbt forced-color-adjust hier BEWUSST an
141
+ // den Labeltext - der steht auf der Highlight-Flaeche. Icons folgen nur mit
142
+ // fill/stroke="currentColor".
143
+ // -------------------------------------------------------------------------
144
+
145
+ @mixin fc-selected($surface: Highlight, $ink: HighlightText) {
146
+ forced-color-adjust: none;
147
+ background-color: $surface;
148
+ border-color: $surface;
149
+ color: $ink;
150
+ }
151
+
152
+ /// Gegenstueck zu fc-selected - noetig, weil der Container in beiden
153
+ /// Zustaenden aus der Automatik faellt.
154
+ @mixin fc-unselected($surface: Canvas, $ink: CanvasText) {
155
+ forced-color-adjust: none;
156
+ background-color: $surface;
157
+ border-color: $ink;
158
+ color: $ink;
159
+ }
@@ -30,7 +30,6 @@
30
30
  display: flex;
31
31
  justify-content: space-between;
32
32
  align-items: center;
33
- padding: 0 $base-gap * 4 0 0;
34
33
  gap: $base-gap * 2;
35
34
  width: 100%;
36
35
 
@@ -56,6 +55,12 @@
56
55
  }
57
56
  }
58
57
 
58
+ .labelWithInfo {
59
+ display: flex;
60
+ align-items: center;
61
+ gap: $base-gap * 2;
62
+ }
63
+
59
64
  .infoRow {
60
65
  display: flex;
61
66
  gap: $base-gap;
@@ -99,14 +104,15 @@
99
104
  transform: rotate(45deg);
100
105
  }
101
106
 
107
+ // ohne das frühere padding-right (16px) der .topRow um 16px angepasst: Tooltip bleibt, wo er war
102
108
  &.adjustRight {
103
109
  left: auto;
104
- right: -40px;
110
+ right: -24px;
105
111
 
106
112
  &::after {
107
113
  content: "";
108
114
  bottom: -10px;
109
- right: 40px;
115
+ right: 24px;
110
116
  left: initial;
111
117
  }
112
118
  }
@@ -182,6 +188,11 @@ textarea {
182
188
  }
183
189
  }
184
190
 
191
+ // Reset-Button unter "Ihre Auswahl" steht in keinem .formInput: gleicher Abstand zum nächsten Feld
192
+ .addressResetBtn {
193
+ margin-bottom: $base-gap * 5;
194
+ }
195
+
185
196
  /* TEXT INPUT */
186
197
  .formInput, fieldset.formInput {
187
198
  display: flex;
@@ -351,6 +362,61 @@ input[type="radio"] {
351
362
  outline: 2px solid white;
352
363
  outline-offset: $bsr-border-width-m * -1 - 3px;
353
364
  }
365
+
366
+ // FORCED COLORS: Der Punkt entsteht oben aus background-color plus einem
367
+ // weissen outline mit negativem Offset als Innenring. background-color wird
368
+ // im Kontrastmodus auf Canvas geflacht und outline-color ohnehin ersetzt -
369
+ // der Punkt verschwindet also. Innenring-Trick deshalb abschalten und den
370
+ // Punkt als Gradient in Nutzerfarben zeichnen.
371
+ @include forced-colors {
372
+ @include fc-control-box;
373
+
374
+ outline: none;
375
+
376
+ &:hover,
377
+ &:active {
378
+ @include fc-control-box;
379
+
380
+ outline: none;
381
+ }
382
+
383
+ &:checked {
384
+ @include fc-control-box;
385
+ @include fc-indicator-radio;
386
+
387
+ outline: none;
388
+ }
389
+
390
+ &:disabled {
391
+ @include fc-control-box-disabled;
392
+
393
+ outline: none;
394
+ }
395
+
396
+ &:disabled:checked {
397
+ @include fc-control-box-disabled;
398
+ @include fc-indicator-radio($color: GrayText);
399
+
400
+ outline: none;
401
+ }
402
+
403
+ &:focus,
404
+ &:focus-visible {
405
+ @include fc-focus-ring-full;
406
+ }
407
+ }
408
+ }
409
+
410
+ // Kein Rot in der Palette: Fehler bleibt ueber die dickere Kontur
411
+ // (border-width wird nicht ueberschrieben) + Fehlermeldung erkennbar.
412
+ // Bewusst NICHT in den Block oben verschachtelt: `.formInput.error &` wuerde
413
+ // unter dem .bsr-uikit-Wrapper `.formInput.error .bsr-uikit input` ergeben,
414
+ // und .formInput liegt innerhalb des Wrappers.
415
+ @include forced-colors {
416
+ .formInput.error input[type="radio"] {
417
+ border-color: CanvasText;
418
+ outline: none;
419
+ }
354
420
  }
355
421
  button {
356
422
  text-underline-offset: 3px;
@@ -488,6 +554,46 @@ form input[type="checkbox"]:focus + label:before {
488
554
  box-shadow: 0 0 0 0.2rem rgba(255, 124.95, 38.25, 0.5);
489
555
  }
490
556
 
557
+ // FORCED COLORS: Der Haken oben ist ein url()-SVG und wird nicht umgefaerbt,
558
+ // Hover und Fokus sind reine box-shadow und verschwinden. Der Input selbst ist
559
+ // visuell versteckt, Box und Indikator liegen auf label:before - deshalb muss
560
+ // auch der Fokusring dorthin.
561
+ @include forced-colors {
562
+ form input[type="checkbox"] + label:before {
563
+ @include fc-control-box;
564
+ }
565
+
566
+ // Keine graue Hover-Vorschau: Hover zeigt oben nur eine dickere Kontur
567
+ // (border-width, keine Farbe - bleibt im Kontrastmodus erhalten). Ein Haken
568
+ // bei Hover wuerde einen nicht gesetzten Zustand vortaeuschen.
569
+
570
+ form input[type="checkbox"]:checked + label:before,
571
+ form input[type="checkbox"]:checked + label:hover:before {
572
+ @include fc-control-box;
573
+ @include fc-indicator-check;
574
+ }
575
+
576
+ // NICHT :read-only mitnehmen - das matcht JEDE Checkbox, weil :read-write
577
+ // nur fuer textuell editierbare Elemente gilt.
578
+ form input[type="checkbox"]:disabled + label:before {
579
+ @include fc-control-box-disabled;
580
+ }
581
+
582
+ form input[type="checkbox"]:disabled:checked + label:before {
583
+ @include fc-control-box-disabled;
584
+ @include fc-indicator-check($color: GrayText);
585
+ }
586
+
587
+ form input[type="checkbox"]:focus + label:before,
588
+ form input[type="checkbox"]:focus-visible + label:before {
589
+ @include fc-focus-ring-full;
590
+ }
591
+
592
+ .formInput.error input[type="checkbox"] + label:before {
593
+ border-color: CanvasText;
594
+ }
595
+ }
596
+
491
597
  /* TAG */
492
598
  .tag {
493
599
  position: relative;