@overmap-ai/core 1.0.51-hover-cards.0 → 1.0.51-qr-field.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.
@@ -12,6 +12,7 @@ export declare const CompleteFieldTypeToClsMapping: {
12
12
  text: typeof import('../fields/StringOrTextFields/TextField/TextField').TextField;
13
13
  custom: typeof import('../fields/CustomField').CustomField;
14
14
  upload: typeof import('../fields/UploadField').UploadField;
15
+ qr: typeof import('../fields/QrField/QrField').QrField;
15
16
  "multi-string": typeof import('../fields/MultiStringField/MultiStringField').MultiStringField;
16
17
  "multi-select": typeof import('../fields/SelectField/MultiSelectField').MultiSelectField;
17
18
  };
@@ -12,7 +12,7 @@ export declare function insert<T>(list: T[] | undefined, index: number, value: T
12
12
  export declare function remove<T>(list: T[], index: number): T[];
13
13
  export declare const makeIdentifier: (existing: unknown, label: string) => string;
14
14
  export declare const findFieldByIdentifier: (fields: ISerializedField[], identifier?: string) => ISerializedField | null;
15
- export declare const makeConditionalSourceFields: (sections: SerializedFieldSection[], index: number) => (import("../typings").SerializedTextField | import("../typings").SerializedBooleanField | import("../typings").SerializedNumberField | import("../typings").SerializedDateField | import("../typings").SerializedStringField | import("../typings").SerializedSelectField | import("../typings").SerializedMultiStringField | import("../typings").SerializedMultiSelectField | import("../typings").SerializedUploadField)[];
15
+ export declare const makeConditionalSourceFields: (sections: SerializedFieldSection[], index: number) => (import("../typings").SerializedTextField | import("../typings").SerializedBooleanField | import("../typings").SerializedNumberField | import("../typings").SerializedDateField | import("../typings").SerializedStringField | import("../typings").SerializedSelectField | import("../typings").SerializedMultiStringField | import("../typings").SerializedMultiSelectField | import("../typings").SerializedUploadField | import("../typings").SerializedQrField)[];
16
16
  export type NewFieldInitialValues = Omit<ISerializedField, "identifier"> & {
17
17
  label: string;
18
18
  };
@@ -0,0 +1,21 @@
1
+ import { ReactNode } from "react";
2
+ import { RiQrCodeLine } from "react-icons/ri";
3
+ import { BaseField, ChildFieldOptions } from "../BaseField";
4
+ import { ISerializedField, SerializedQrField } from "../../typings";
5
+ import { ComponentProps } from "../typings";
6
+ export declare const emptyQrField: {
7
+ type: string;
8
+ label: string;
9
+ description: string;
10
+ required: boolean;
11
+ };
12
+ export declare class QrField extends BaseField<string, "qr"> {
13
+ static readonly fieldTypeName = "QR";
14
+ static readonly fieldTypeDescription = "Used for scanning/reading QR codes.";
15
+ readonly onlyValidateAfterTouched = false;
16
+ static Icon: typeof RiQrCodeLine;
17
+ constructor(options: ChildFieldOptions<string>);
18
+ serialize(): SerializedQrField;
19
+ static deserialize(data: ISerializedField): QrField;
20
+ getInput(props: ComponentProps<QrField>): ReactNode;
21
+ }
@@ -0,0 +1,10 @@
1
+ /// <reference types="react" />
2
+ import { ComponentProps } from "../typings";
3
+ import { QrField } from "./QrField";
4
+ export declare const QrInput: import("react").MemoExoticComponent<(props: ComponentProps<QrField>) => import("react/jsx-runtime").JSX.Element>;
5
+ interface QrScannerProps {
6
+ onQrScan: (data: string) => void;
7
+ onClose: () => void;
8
+ }
9
+ export declare const QrScanner: import("react").MemoExoticComponent<(props: QrScannerProps) => import("react/jsx-runtime").JSX.Element>;
10
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from "./QrField";
2
+ export * from "./QrInput";
@@ -6,6 +6,7 @@ import { MultiSelectField, SelectField } from "./SelectField";
6
6
  import { CustomField } from "./CustomField";
7
7
  import { MultiStringField } from "./MultiStringField";
8
8
  import { UploadField } from "./UploadField";
9
+ import { QrField } from "./QrField";
9
10
  export declare const FieldTypeToClsMapping: {
10
11
  readonly date: typeof DateField;
11
12
  readonly number: typeof NumberField;
@@ -15,6 +16,7 @@ export declare const FieldTypeToClsMapping: {
15
16
  readonly text: typeof TextField;
16
17
  readonly custom: typeof CustomField;
17
18
  readonly upload: typeof UploadField;
19
+ readonly qr: typeof QrField;
18
20
  readonly "multi-string": typeof MultiStringField;
19
21
  readonly "multi-select": typeof MultiSelectField;
20
22
  };
@@ -77,6 +79,12 @@ export declare const FieldTypeToEmptyFieldMapping: {
77
79
  description: string;
78
80
  required: boolean;
79
81
  };
82
+ readonly qr: {
83
+ type: string;
84
+ label: string;
85
+ description: string;
86
+ required: boolean;
87
+ };
80
88
  readonly "multi-string": {
81
89
  type: string;
82
90
  minimum_length: number;
@@ -5,6 +5,7 @@ export * from "./StringOrTextFields";
5
5
  export * from "./BooleanField";
6
6
  export * from "./SelectField";
7
7
  export * from "./MultiStringField";
8
+ export * from "./QrField";
8
9
  export * from "./FieldSection";
9
10
  export * from "./utils";
10
11
  export * from "./hooks";
@@ -16,7 +16,7 @@ import { AnyField, BaseField } from "./fields";
16
16
  export type Form = Record<string, FieldValue | Promise<File>[]>;
17
17
  /** Helper type that extracts the TValue type from a BaseField. */
18
18
  export type ValueOfField<Type extends AnyField> = Type extends BaseField<infer TValue> ? TValue : never;
19
- export type FieldTypeIdentifier = "string" | "text" | "boolean" | "number" | "date" | "select" | "custom" | "section" | "multi-string" | "multi-select" | "upload";
19
+ export type FieldTypeIdentifier = "string" | "text" | "boolean" | "number" | "date" | "select" | "custom" | "section" | "multi-string" | "multi-select" | "upload" | "qr";
20
20
  export interface BaseSerializedObject<TIdentifier extends FieldTypeIdentifier = FieldTypeIdentifier> {
21
21
  description?: string | null;
22
22
  identifier: string;
@@ -50,6 +50,9 @@ export interface SerializedStringField extends BaseSerializedStringField {
50
50
  type: "string";
51
51
  input_type?: StringInputType;
52
52
  }
53
+ export interface SerializedQrField extends BaseSerializedField {
54
+ type: "qr";
55
+ }
53
56
  export interface SerializedTextField extends BaseSerializedStringField {
54
57
  type: "text";
55
58
  }
@@ -96,5 +99,5 @@ export interface SerializedUploadField extends BaseSerializedField {
96
99
  */
97
100
  maximum_files?: number;
98
101
  }
99
- export type ISerializedField = SerializedTextField | SerializedBooleanField | SerializedNumberField | SerializedDateField | SerializedStringField | SerializedSelectField | SerializedFieldSection | SerializedMultiStringField | SerializedMultiSelectField | SerializedUploadField;
102
+ export type ISerializedField = SerializedTextField | SerializedBooleanField | SerializedNumberField | SerializedDateField | SerializedStringField | SerializedSelectField | SerializedFieldSection | SerializedMultiStringField | SerializedMultiSelectField | SerializedUploadField | SerializedQrField;
100
103
  export {};
@@ -8,7 +8,7 @@ var _a;
8
8
  import * as React from "react";
9
9
  import React__default, { useState, useEffect, useRef, memo, useMemo, useCallback, createContext, createElement, useContext, forwardRef, Children, isValidElement, cloneElement, Fragment as Fragment$1, useLayoutEffect, useReducer, lazy, Suspense } from "react";
10
10
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
11
- import { unsafeShowToast, AlertDialogProvider, ToastProvider, DefaultTheme, Flex as Flex$1, IconButton, RiIcon, Text as Text$1, useSeverityColor, Checkbox, TextArea, Select, useToast, Badge, MultiSelect, useViewportSize, Overlay, ButtonGroup, Spinner, IconColorUtility, Tooltip, Popover, useSize, ToggleButton, Separator, OvermapItem, Button, ButtonList, divButtonProps, OvermapDropdownMenu, Input, useAlertDialog } from "@overmap-ai/blocks";
11
+ import { unsafeShowToast, AlertDialogProvider, ToastProvider, DefaultTheme, Flex as Flex$1, IconButton, RiIcon, Text as Text$1, useSeverityColor, Checkbox, TextArea, Select, useToast, Badge, MultiSelect, Overlay, Button, Spinner, useViewportSize, ButtonGroup, IconColorUtility, Tooltip, Popover, useSize, ToggleButton, Separator, OvermapItem, ButtonList, divButtonProps, OvermapDropdownMenu, Input, useAlertDialog } from "@overmap-ai/blocks";
12
12
  import { DepGraph } from "dependency-graph";
13
13
  import { offline as offline$1 } from "@redux-offline/redux-offline";
14
14
  import offlineConfig from "@redux-offline/redux-offline/lib/defaults";
@@ -27,6 +27,7 @@ import { useField, useFormikContext, useFormik, FormikProvider } from "formik";
27
27
  import get from "lodash.get";
28
28
  import Linkify from "linkify-react";
29
29
  import { DragDropContext, Droppable, Draggable } from "@hello-pangea/dnd";
30
+ import QrScannerAPI from "qr-scanner";
30
31
  import { read, utils } from "xlsx";
31
32
  import { pdfjs, Document, Page } from "react-pdf";
32
33
  import "react-pdf/dist/Page/AnnotationLayer.css";
@@ -1572,9 +1573,6 @@ const selectHiddenCategoryCount = (state) => {
1572
1573
  hiddenCategoryCount++;
1573
1574
  return hiddenCategoryCount;
1574
1575
  };
1575
- const selectIssueCountOfCategory = (categoryId) => (state) => {
1576
- return Object.values(state.issueReducer.issues).filter((issue) => issue.category === categoryId).length;
1577
- };
1578
1576
  const categoryReducer = categorySlice.reducer;
1579
1577
  function setAttachments(state, action) {
1580
1578
  state.attachments = {};
@@ -8234,7 +8232,7 @@ const tabTrigger = "_tabTrigger_1w0fq_69";
8234
8232
  const patchfieldBorder = "_patchfieldBorder_1w0fq_73";
8235
8233
  const title = "_title_1w0fq_73";
8236
8234
  const error = "_error_1w0fq_89";
8237
- const styles$c = {
8235
+ const styles$d = {
8238
8236
  description: description$2,
8239
8237
  floatingButtonContainer: floatingButtonContainer$2,
8240
8238
  FullScreenImageContainer: FullScreenImageContainer$2,
@@ -8355,7 +8353,7 @@ const fileName$1 = "_fileName_10o76_31";
8355
8353
  const longIconButton$1 = "_longIconButton_10o76_36";
8356
8354
  const previewImage$1 = "_previewImage_10o76_42";
8357
8355
  const FullScreenImage$1 = "_FullScreenImage_10o76_12";
8358
- const styles$b = {
8356
+ const styles$c = {
8359
8357
  description: description$1,
8360
8358
  floatingButtonContainer: floatingButtonContainer$1,
8361
8359
  FullScreenImageContainer: FullScreenImageContainer$1,
@@ -8379,7 +8377,7 @@ const FullScreenImagePreview = memo((props) => {
8379
8377
  /* @__PURE__ */ jsx(
8380
8378
  "button",
8381
8379
  {
8382
- className: styles$b.FullScreenImageContainer,
8380
+ className: styles$c.FullScreenImageContainer,
8383
8381
  type: "button",
8384
8382
  onClick: () => {
8385
8383
  setShowPreview(false);
@@ -8387,7 +8385,7 @@ const FullScreenImagePreview = memo((props) => {
8387
8385
  children: /* @__PURE__ */ jsx(
8388
8386
  "img",
8389
8387
  {
8390
- className: styles$b.FullScreenImage,
8388
+ className: styles$c.FullScreenImage,
8391
8389
  src: url,
8392
8390
  alt: name,
8393
8391
  onClick: (e) => {
@@ -8397,11 +8395,11 @@ const FullScreenImagePreview = memo((props) => {
8397
8395
  )
8398
8396
  }
8399
8397
  ),
8400
- /* @__PURE__ */ jsxs(Flex$1, { className: styles$b.TopBarContainer, align: "center", children: [
8398
+ /* @__PURE__ */ jsxs(Flex$1, { className: styles$c.TopBarContainer, align: "center", children: [
8401
8399
  /* @__PURE__ */ jsx(
8402
8400
  IconButton,
8403
8401
  {
8404
- className: styles$b.longIconButton,
8402
+ className: styles$c.longIconButton,
8405
8403
  variant: "soft",
8406
8404
  "aria-label": "Exit preview",
8407
8405
  onClick: () => {
@@ -8410,11 +8408,11 @@ const FullScreenImagePreview = memo((props) => {
8410
8408
  children: /* @__PURE__ */ jsx(RiIcon, { icon: "RiArrowLeftLine" })
8411
8409
  }
8412
8410
  ),
8413
- /* @__PURE__ */ jsx(Text$1, { className: styles$b.fileName, children: name }),
8411
+ /* @__PURE__ */ jsx(Text$1, { className: styles$c.fileName, children: name }),
8414
8412
  /* @__PURE__ */ jsx(
8415
8413
  IconButton,
8416
8414
  {
8417
- className: styles$b.longIconButton,
8415
+ className: styles$c.longIconButton,
8418
8416
  variant: "soft",
8419
8417
  "aria-label": `Download ${name}`,
8420
8418
  onClick: handleDownload,
@@ -8442,7 +8440,7 @@ const InputWithLabel = (props) => {
8442
8440
  /* @__PURE__ */ jsx(
8443
8441
  "img",
8444
8442
  {
8445
- className: styles$b.previewImage,
8443
+ className: styles$c.previewImage,
8446
8444
  src: resolvedImageURL,
8447
8445
  alt: resolvedImage.name,
8448
8446
  onClick: () => {
@@ -8470,7 +8468,7 @@ const InputWithHelpText = (props) => {
8470
8468
  const { helpText, children, severity } = props;
8471
8469
  return /* @__PURE__ */ jsxs(Flex$1, { direction: "column", gap: "1", children: [
8472
8470
  children,
8473
- /* @__PURE__ */ jsx(Flex$1, { direction: "column", children: /* @__PURE__ */ jsx(Text$1, { size: "1", severity, className: styles$b.description, children: helpText }) })
8471
+ /* @__PURE__ */ jsx(Flex$1, { direction: "column", children: /* @__PURE__ */ jsx(Text$1, { size: "1", severity, className: styles$c.description, children: helpText }) })
8474
8472
  ] });
8475
8473
  };
8476
8474
  const InputWithLabelAndHelpText = (props) => {
@@ -8704,6 +8702,9 @@ function RiArrowUpLine(props) {
8704
8702
  function RiCalendarLine(props) {
8705
8703
  return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24", "fill": "currentColor" }, "child": [{ "tag": "path", "attr": { "d": "M9 1V3H15V1H17V3H21C21.5523 3 22 3.44772 22 4V20C22 20.5523 21.5523 21 21 21H3C2.44772 21 2 20.5523 2 20V4C2 3.44772 2.44772 3 3 3H7V1H9ZM20 11H4V19H20V11ZM7 5H4V9H20V5H17V7H15V5H9V7H7V5Z" }, "child": [] }] })(props);
8706
8704
  }
8705
+ function RiQrCodeLine(props) {
8706
+ return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24", "fill": "currentColor" }, "child": [{ "tag": "path", "attr": { "d": "M16 17V16H13V13H16V15H18V17H17V19H15V21H13V18H15V17H16ZM21 21H17V19H19V17H21V21ZM3 3H11V11H3V3ZM5 5V9H9V5H5ZM13 3H21V11H13V3ZM15 5V9H19V5H15ZM3 13H11V21H3V13ZM5 15V19H9V15H5ZM18 13H21V15H18V13ZM6 6H8V8H6V6ZM6 16H8V18H6V16ZM16 6H18V8H16V6Z" }, "child": [] }] })(props);
8707
+ }
8707
8708
  function RiFileCopyLine(props) {
8708
8709
  return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24", "fill": "currentColor" }, "child": [{ "tag": "path", "attr": { "d": "M6.9998 6V3C6.9998 2.44772 7.44752 2 7.9998 2H19.9998C20.5521 2 20.9998 2.44772 20.9998 3V17C20.9998 17.5523 20.5521 18 19.9998 18H16.9998V20.9991C16.9998 21.5519 16.5499 22 15.993 22H4.00666C3.45059 22 3 21.5554 3 20.9991L3.0026 7.00087C3.0027 6.44811 3.45264 6 4.00942 6H6.9998ZM5.00242 8L5.00019 20H14.9998V8H5.00242ZM8.9998 6H16.9998V16H18.9998V4H8.9998V6Z" }, "child": [] }] })(props);
8709
8710
  }
@@ -9607,9 +9608,9 @@ const Inset = React.forwardRef((props, forwardedRef) => {
9607
9608
  return React.createElement("div", { ...insetProps, ref: forwardedRef, className: classNames("rt-Inset", className, withBreakpoints(side, "rt-r-side"), withBreakpoints(clip, "rt-r-clip"), withBreakpoints(p, "rt-r-p"), withBreakpoints(px, "rt-r-px"), withBreakpoints(py, "rt-r-py"), withBreakpoints(pt, "rt-r-pt"), withBreakpoints(pr, "rt-r-pr"), withBreakpoints(pb, "rt-r-pb"), withBreakpoints(pl, "rt-r-pl"), withMarginProps(marginProps)) });
9608
9609
  });
9609
9610
  Inset.displayName = "Inset";
9610
- const sizes$7 = ["1", "2", "3", "4", "5", "6", "7", "8", "9"];
9611
+ const sizes$8 = ["1", "2", "3", "4", "5", "6", "7", "8", "9"];
9611
9612
  const headingPropDefs = {
9612
- size: { type: "enum", values: sizes$7, default: "6", responsive: true },
9613
+ size: { type: "enum", values: sizes$8, default: "6", responsive: true },
9613
9614
  weight: { ...weightProp, default: "bold" },
9614
9615
  align: alignProp,
9615
9616
  trim: trimProp,
@@ -9622,9 +9623,9 @@ const Heading = React.forwardRef((props, forwardedRef) => {
9622
9623
  return React.createElement($5e63c961fc1ce211$export$8c6ed5c666ac1360, { "data-accent-color": color, ...headingProps, ref: forwardedRef, className: classNames("rt-Heading", className, withBreakpoints(size, "rt-r-size"), withBreakpoints(weight, "rt-r-weight"), withBreakpoints(align, "rt-r-ta"), withBreakpoints(trim, "rt-r-lt"), { "rt-high-contrast": highContrast }, withMarginProps(marginProps)) }, asChild ? children : React.createElement(Tag, null, children));
9623
9624
  });
9624
9625
  Heading.displayName = "Heading";
9625
- const sizes$6 = ["1", "2", "3", "4", "5", "6", "7", "8", "9"];
9626
+ const sizes$7 = ["1", "2", "3", "4", "5", "6", "7", "8", "9"];
9626
9627
  const textPropDefs = {
9627
- size: { type: "enum", values: sizes$6, default: void 0, responsive: true },
9628
+ size: { type: "enum", values: sizes$7, default: void 0, responsive: true },
9628
9629
  weight: weightProp,
9629
9630
  align: alignProp,
9630
9631
  trim: trimProp,
@@ -9637,6 +9638,21 @@ const Text = React.forwardRef((props, forwardedRef) => {
9637
9638
  return React.createElement($5e63c961fc1ce211$export$8c6ed5c666ac1360, { "data-accent-color": color, ...textProps, ref: forwardedRef, className: classNames("rt-Text", className, withBreakpoints(size, "rt-r-size"), withBreakpoints(weight, "rt-r-weight"), withBreakpoints(align, "rt-r-ta"), withBreakpoints(trim, "rt-r-lt"), { "rt-high-contrast": highContrast }, withMarginProps(marginProps)) }, asChild ? children : React.createElement(Tag, null, children));
9638
9639
  });
9639
9640
  Text.displayName = "Text";
9641
+ const sizes$6 = ["1", "2", "3", "4", "5", "6", "7", "8", "9"];
9642
+ const variants$4 = ["solid", "soft", "outline", "ghost"];
9643
+ const codePropDefs = {
9644
+ size: { type: "enum", values: sizes$6, default: void 0, responsive: true },
9645
+ variant: { type: "enum", values: variants$4, default: "soft" },
9646
+ weight: weightProp,
9647
+ color: colorProp,
9648
+ highContrast: highContrastProp
9649
+ };
9650
+ const Code = React.forwardRef((props, forwardedRef) => {
9651
+ const { rest: marginRest, ...marginProps } = extractMarginProps(props);
9652
+ const { className, size = codePropDefs.size.default, variant = codePropDefs.variant.default, weight = codePropDefs.weight.default, color = codePropDefs.color.default, highContrast = codePropDefs.highContrast.default, ...codeProps } = marginRest;
9653
+ return React.createElement("code", { "data-accent-color": color, ...codeProps, ref: forwardedRef, className: classNames("rt-Code", className, withBreakpoints(size, "rt-r-size"), `rt-variant-${variant}`, withBreakpoints(weight, "rt-r-weight"), { "rt-high-contrast": highContrast }, withMarginProps(marginProps)) });
9654
+ });
9655
+ Code.displayName = "Code";
9640
9656
  const Em = React.forwardRef((props, forwardedRef) => React.createElement("em", { ...props, ref: forwardedRef, className: classNames("rt-Em", props.className) }));
9641
9657
  Em.displayName = "Em";
9642
9658
  const Strong = React.forwardRef((props, forwardedRef) => React.createElement("strong", { ...props, ref: forwardedRef, className: classNames("rt-Strong", props.className) }));
@@ -12027,7 +12043,7 @@ __publicField(StringOrTextField, "_validateMax", (path) => (value, allValues) =>
12027
12043
  });
12028
12044
  const clickableLinkContainer = "_clickableLinkContainer_1ace7_1";
12029
12045
  const TextFieldInputCopy = "_TextFieldInputCopy_1ace7_5";
12030
- const styles$a = {
12046
+ const styles$b = {
12031
12047
  clickableLinkContainer,
12032
12048
  TextFieldInputCopy
12033
12049
  };
@@ -12056,13 +12072,13 @@ const StringInput = memo((props) => {
12056
12072
  placeholder: field.placeholder,
12057
12073
  color
12058
12074
  }
12059
- ) : /* @__PURE__ */ jsxs(TextField$1.Root, { className: styles$a.clickableLinkContainer, children: [
12075
+ ) : /* @__PURE__ */ jsxs(TextField$1.Root, { className: styles$b.clickableLinkContainer, children: [
12060
12076
  /* @__PURE__ */ jsx(
12061
12077
  "div",
12062
12078
  {
12063
12079
  className: classNames$1(
12064
12080
  "rt-TextFieldInput rt-r-size-2 rt-variant-surface",
12065
- styles$a.TextFieldInputCopy
12081
+ styles$b.TextFieldInputCopy
12066
12082
  ),
12067
12083
  children: /* @__PURE__ */ jsx(
12068
12084
  Linkify,
@@ -12754,6 +12770,158 @@ __publicField(_MultiSelectField, "fieldTypeName", "Multi-select");
12754
12770
  __publicField(_MultiSelectField, "fieldTypeDescription", "Allows the user to select a multiple options from a list of options.");
12755
12771
  __publicField(_MultiSelectField, "Icon", RiCheckboxLine);
12756
12772
  let MultiSelectField = _MultiSelectField;
12773
+ const QrScannerWrapper = "_QrScannerWrapper_1puz3_1";
12774
+ const styles$a = {
12775
+ QrScannerWrapper
12776
+ };
12777
+ const QrInput = memo((props) => {
12778
+ const [{ inputId, labelId, label, helpText, size, severity, showInputOnly, field, fieldProps }, rest] = useFormikInput(props);
12779
+ const [showQrScanner, setShowQrScanner] = useState(false);
12780
+ const value = fieldProps.value;
12781
+ const handleQrScan = useCallback(
12782
+ (data) => {
12783
+ fieldProps.onChange({ target: { value: data } });
12784
+ setShowQrScanner(false);
12785
+ },
12786
+ [fieldProps]
12787
+ );
12788
+ const handleClearScanResult = useCallback(() => {
12789
+ fieldProps.onChange({ target: { value: "" } });
12790
+ }, [fieldProps]);
12791
+ const handleScanButtonClicked = useCallback(() => {
12792
+ setShowQrScanner(true);
12793
+ }, []);
12794
+ const handleQrScannerClose = useCallback(() => {
12795
+ setShowQrScanner(false);
12796
+ }, []);
12797
+ return /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText, severity, children: /* @__PURE__ */ jsxs(
12798
+ InputWithLabel,
12799
+ {
12800
+ size,
12801
+ severity,
12802
+ inputId,
12803
+ labelId,
12804
+ label: showInputOnly ? label : "",
12805
+ image: showInputOnly ? void 0 : field.image,
12806
+ flexProps: { direction: "column", justify: "start", align: "start", gap: "1" },
12807
+ children: [
12808
+ /* @__PURE__ */ jsx(
12809
+ Overlay,
12810
+ {
12811
+ open: showQrScanner,
12812
+ content: () => /* @__PURE__ */ jsx(QrScanner, { onQrScan: handleQrScan, onClose: handleQrScannerClose }),
12813
+ onOpenChange: setShowQrScanner
12814
+ }
12815
+ ),
12816
+ /* @__PURE__ */ jsxs(Flex, { width: "max-content", gap: "1", align: "center", children: [
12817
+ /* @__PURE__ */ jsxs(Button, { ...rest, variant: "soft", onClick: handleScanButtonClicked, children: [
12818
+ /* @__PURE__ */ jsx(RiIcon, { icon: "RiQrCodeLine" }),
12819
+ "Scan"
12820
+ ] }),
12821
+ value && /* @__PURE__ */ jsx(Text, { color: "jade", size: "1", children: /* @__PURE__ */ jsx(RiIcon, { icon: "RiCheckLine", style: { verticalAlign: "bottom" } }) })
12822
+ ] }),
12823
+ value && /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsxs(Flex, { width: "max-content", gap: "2", align: "center", children: [
12824
+ /* @__PURE__ */ jsx(Code, { color: "gray", highContrast: true, children: value }),
12825
+ /* @__PURE__ */ jsx(
12826
+ IconButton,
12827
+ {
12828
+ severity: "info",
12829
+ variant: "ghost",
12830
+ "aria-label": "delete",
12831
+ size: "small",
12832
+ onClick: handleClearScanResult,
12833
+ children: /* @__PURE__ */ jsx(RiIcon, { icon: "RiCloseLine" })
12834
+ }
12835
+ )
12836
+ ] }) })
12837
+ ]
12838
+ }
12839
+ ) });
12840
+ });
12841
+ QrInput.displayName = "QrInput";
12842
+ const QrScanner = memo((props) => {
12843
+ const { onQrScan, onClose } = props;
12844
+ const videoRef = useRef(null);
12845
+ const [isScannerLoading, setIsScannerLoading] = useState(false);
12846
+ useEffect(() => {
12847
+ if (!videoRef.current)
12848
+ return;
12849
+ const qrScanner = new QrScannerAPI(
12850
+ videoRef.current,
12851
+ (result) => {
12852
+ const data = result.data;
12853
+ onQrScan(data);
12854
+ qrScanner.destroy();
12855
+ },
12856
+ {
12857
+ highlightCodeOutline: true,
12858
+ highlightScanRegion: true,
12859
+ maxScansPerSecond: 1
12860
+ }
12861
+ );
12862
+ setIsScannerLoading(true);
12863
+ qrScanner.start().then(() => {
12864
+ setIsScannerLoading(false);
12865
+ }).catch(() => {
12866
+ setIsScannerLoading(false);
12867
+ });
12868
+ }, [onQrScan]);
12869
+ return /* @__PURE__ */ jsxs(
12870
+ Flex,
12871
+ {
12872
+ className: styles$a.QrScannerWrapper,
12873
+ width: "100%",
12874
+ height: "100%",
12875
+ direction: "column",
12876
+ gap: "2",
12877
+ justify: "center",
12878
+ position: "relative",
12879
+ children: [
12880
+ /* @__PURE__ */ jsx(Flex, { width: "100%", position: "absolute", top: "0", p: "2", children: /* @__PURE__ */ jsx(IconButton, { "aria-label": "close", variant: "soft", severity: "info", highContrast: true, onClick: onClose, children: /* @__PURE__ */ jsx(RiIcon, { icon: "RiCloseLine" }) }) }),
12881
+ /* @__PURE__ */ jsxs(Box, { style: { maxWidth: "100%", maxHeight: "100%" }, position: "relative", children: [
12882
+ /* @__PURE__ */ jsx("video", { ref: videoRef, style: { width: "100%", height: "100%" } }),
12883
+ isScannerLoading && /* @__PURE__ */ jsx(
12884
+ Flex,
12885
+ {
12886
+ position: "absolute",
12887
+ inset: "0",
12888
+ style: { background: "var(--color-background)" },
12889
+ justify: "center",
12890
+ align: "center",
12891
+ children: /* @__PURE__ */ jsx(Spinner, {})
12892
+ }
12893
+ )
12894
+ ] })
12895
+ ]
12896
+ }
12897
+ );
12898
+ });
12899
+ QrScanner.displayName = "QrScanner";
12900
+ const emptyQrField = {
12901
+ ...emptyBaseField,
12902
+ type: "qr"
12903
+ };
12904
+ const _QrField = class _QrField extends BaseField {
12905
+ constructor(options) {
12906
+ super({ ...options, type: "qr" });
12907
+ __publicField(this, "onlyValidateAfterTouched", false);
12908
+ }
12909
+ serialize() {
12910
+ return super._serialize();
12911
+ }
12912
+ static deserialize(data) {
12913
+ if (data.type !== "qr")
12914
+ throw new Error("Type mismatch.");
12915
+ return new _QrField(data);
12916
+ }
12917
+ getInput(props) {
12918
+ return /* @__PURE__ */ jsx(QrInput, { ...props, field: this });
12919
+ }
12920
+ };
12921
+ __publicField(_QrField, "fieldTypeName", "QR");
12922
+ __publicField(_QrField, "fieldTypeDescription", "Used for scanning/reading QR codes.");
12923
+ __publicField(_QrField, "Icon", RiQrCodeLine);
12924
+ let QrField = _QrField;
12757
12925
  const FieldInputCloner = memo((props) => {
12758
12926
  const { field, ...rest } = props;
12759
12927
  const [{ value: identifier }] = useField(field.options.clonedFieldIdentifier);
@@ -14011,6 +14179,7 @@ const FieldTypeToClsMapping = {
14011
14179
  text: TextField,
14012
14180
  custom: CustomField,
14013
14181
  upload: UploadField,
14182
+ qr: QrField,
14014
14183
  // TODO: Underscore
14015
14184
  "multi-string": MultiStringField,
14016
14185
  "multi-select": MultiSelectField
@@ -14024,6 +14193,7 @@ const FieldTypeToEmptyFieldMapping = {
14024
14193
  text: emptyTextField,
14025
14194
  custom: emptyCustomField,
14026
14195
  upload: emptyUploadField,
14196
+ qr: emptyQrField,
14027
14197
  // TODO: Underscore
14028
14198
  "multi-string": emptyMultiStringField,
14029
14199
  "multi-select": emptyMultiSelectField
@@ -14111,7 +14281,7 @@ const FieldSectionLayout = memo((props) => {
14111
14281
  return /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsxs(Flex$1, { direction: "column", gap: "3", children: [
14112
14282
  /* @__PURE__ */ jsxs(Flex$1, { direction: "column", children: [
14113
14283
  /* @__PURE__ */ jsx(Heading, { as: "h3", size: "3", children: label }),
14114
- /* @__PURE__ */ jsx(Text$1, { className: styles$b.description, children: description2 })
14284
+ /* @__PURE__ */ jsx(Text$1, { className: styles$c.description, children: description2 })
14115
14285
  ] }),
14116
14286
  inputs
14117
14287
  ] }) });
@@ -14354,7 +14524,7 @@ const FormRenderer = memo(
14354
14524
  [schema.title]
14355
14525
  );
14356
14526
  const Description = useMemo(
14357
- () => typeof schema.description === "string" ? /* @__PURE__ */ jsx(Text$1, { className: styles$b.description, children: schema.description }) : schema.description,
14527
+ () => typeof schema.description === "string" ? /* @__PURE__ */ jsx(Text$1, { className: styles$c.description, children: schema.description }) : schema.description,
14358
14528
  [schema.description]
14359
14529
  );
14360
14530
  const inputs = useFieldInputs(schema.fields, { formId: formId2, disabled: readonly });
@@ -14370,7 +14540,7 @@ const FormRenderer = memo(
14370
14540
  !hideDescription && Description
14371
14541
  ] }) }),
14372
14542
  inputs,
14373
- !readonly && /* @__PURE__ */ jsxs(Flex$1, { className: styles$b.floatingButtonContainer, align: "center", justify: "end", gap: "2", children: [
14543
+ !readonly && /* @__PURE__ */ jsxs(Flex$1, { className: styles$c.floatingButtonContainer, align: "center", justify: "end", gap: "2", children: [
14374
14544
  cancelText && /* @__PURE__ */ jsx(Button, { severity: "info", ...buttonProps, type: "button", onClick: onCancel, children: cancelText }),
14375
14545
  /* @__PURE__ */ jsx(Button, { ...buttonProps, type: "submit", disabled: !formik.isValid, children: submitText })
14376
14546
  ] })
@@ -15718,12 +15888,12 @@ const FormBuilder = memo(
15718
15888
  });
15719
15889
  const previewSchema = useMemo(() => formRevisionToSchema(formik.values), [formik.values]);
15720
15890
  return /* @__PURE__ */ jsx(Tabs.Root, { ref, defaultValue: "edit", children: /* @__PURE__ */ jsxs(Flex$1, { direction: "column", gap: "2", children: [
15721
- showTabs && /* @__PURE__ */ jsxs(Tabs.List, { className: classNames$1(styles$c.tabsList, tabsListClassName), children: [
15722
- /* @__PURE__ */ jsx(Tabs.Trigger, { className: styles$c.tabTrigger, value: "edit", children: /* @__PURE__ */ jsxs(Flex$1, { align: "center", gap: "2", children: [
15891
+ showTabs && /* @__PURE__ */ jsxs(Tabs.List, { className: classNames$1(styles$d.tabsList, tabsListClassName), children: [
15892
+ /* @__PURE__ */ jsx(Tabs.Trigger, { className: styles$d.tabTrigger, value: "edit", children: /* @__PURE__ */ jsxs(Flex$1, { align: "center", gap: "2", children: [
15723
15893
  /* @__PURE__ */ jsx(RiIcon, { icon: "RiPencilLine" }),
15724
15894
  "Edit"
15725
15895
  ] }) }),
15726
- /* @__PURE__ */ jsx(Tabs.Trigger, { className: styles$c.tabTrigger, value: "preview", children: /* @__PURE__ */ jsxs(Flex$1, { align: "center", gap: "2", children: [
15896
+ /* @__PURE__ */ jsx(Tabs.Trigger, { className: styles$d.tabTrigger, value: "preview", children: /* @__PURE__ */ jsxs(Flex$1, { align: "center", gap: "2", children: [
15727
15897
  /* @__PURE__ */ jsx(RiIcon, { icon: "RiEyeLine" }),
15728
15898
  "Preview"
15729
15899
  ] }) })
@@ -15747,8 +15917,8 @@ const FormBuilder = memo(
15747
15917
  render: ({ setValue, value, meta }) => /* @__PURE__ */ jsx(InputWithHelpText, { severity: "danger", helpText: meta.error ?? null, children: /* @__PURE__ */ jsx(
15748
15918
  Input,
15749
15919
  {
15750
- className: classNames$1(styles$c.title, {
15751
- [styles$c.error]: meta.error
15920
+ className: classNames$1(styles$d.title, {
15921
+ [styles$d.error]: meta.error
15752
15922
  }),
15753
15923
  placeholder: "Form title",
15754
15924
  value,
@@ -15770,7 +15940,7 @@ const FormBuilder = memo(
15770
15940
  render: ({ setValue, value }) => /* @__PURE__ */ jsx(
15771
15941
  TextArea,
15772
15942
  {
15773
- className: styles$c.description,
15943
+ className: styles$d.description,
15774
15944
  placeholder: "Explain the purpose of this form",
15775
15945
  value,
15776
15946
  onChange: (event) => {
@@ -15788,7 +15958,7 @@ const FormBuilder = memo(
15788
15958
  /* @__PURE__ */ jsx(FieldsEditor, { fieldsOnly }),
15789
15959
  /* @__PURE__ */ jsx(Text$1, { severity: "danger", size: "1", children: typeof formik.errors.fields === "string" && formik.errors.fields })
15790
15960
  ] }),
15791
- /* @__PURE__ */ jsxs(Flex$1, { className: styles$c.floatingButtonContainer, align: "center", justify: "end", gap: "2", children: [
15961
+ /* @__PURE__ */ jsxs(Flex$1, { className: styles$d.floatingButtonContainer, align: "center", justify: "end", gap: "2", children: [
15792
15962
  onCancel && /* @__PURE__ */ jsx(Button, { type: "button", variant: "solid", severity: "info", onClick: onCancel, children: "Cancel" }),
15793
15963
  /* @__PURE__ */ jsx(Button, { type: "submit", children: "Save form" })
15794
15964
  ] })
@@ -15823,6 +15993,9 @@ const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePropert
15823
15993
  NumberInput,
15824
15994
  PatchField,
15825
15995
  PatchFormProvider,
15996
+ QrField,
15997
+ QrInput,
15998
+ QrScanner,
15826
15999
  SelectField,
15827
16000
  SelectInput,
15828
16001
  StringField,
@@ -15837,6 +16010,7 @@ const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePropert
15837
16010
  emptyMultiSelectField,
15838
16011
  emptyMultiStringField,
15839
16012
  emptyNumberField,
16013
+ emptyQrField,
15840
16014
  emptySelectField,
15841
16015
  emptyStringField,
15842
16016
  emptyTextField,
@@ -15927,6 +16101,9 @@ export {
15927
16101
  ProjectFileService,
15928
16102
  ProjectService,
15929
16103
  ProjectType,
16104
+ QrField,
16105
+ QrInput,
16106
+ QrScanner,
15930
16107
  SDKContext,
15931
16108
  SDKProvider,
15932
16109
  SUPPORTED_IMAGE_FILE_TYPES,
@@ -16050,6 +16227,7 @@ export {
16050
16227
  emptyMultiSelectField,
16051
16228
  emptyMultiStringField,
16052
16229
  emptyNumberField,
16230
+ emptyQrField,
16053
16231
  emptySelectField,
16054
16232
  emptyStringField,
16055
16233
  emptyTextField,
@@ -16274,7 +16452,6 @@ export {
16274
16452
  selectIssueAttachment,
16275
16453
  selectIssueAttachmentMapping,
16276
16454
  selectIssueAttachments,
16277
- selectIssueCountOfCategory,
16278
16455
  selectIssueMapping,
16279
16456
  selectIssueUpdateMapping,
16280
16457
  selectIssueUpdatesOfIssue,