@webority/ui-react 0.13.1 → 0.13.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.
@@ -17,13 +17,20 @@
17
17
  * @param {(file: File|null) => void | (files: File[]) => void} props.onChange single-mode → File|null; multiple → File[]
18
18
  * @param {boolean} [props.multiple=false]
19
19
  * @param {string} [props.accept] Defaults to images; pass e.g. "image/*,application/pdf" for mixed.
20
- * @param {number} [props.maxSizeMb] Defaults to the shared DEFAULT_MAX_SIZE_MB.
20
+ * An empty string accepts any file type, and the hint then names no types.
21
+ * @param {number} [props.maxSizeMb] Defaults to the shared DEFAULT_MAX_SIZE_MB. 0 means no size
22
+ * limit: nothing is rejected for its size, and the hint names no size.
21
23
  * @param {boolean} [props.optional=false]
24
+ * @param {boolean} [props.validate=true] Check each pick against `accept` and `maxSizeMb` and show
25
+ * the field's own message for a rejected file. Set false when the caller validates the files
26
+ * itself and shows its own message through `error`: every pick then reaches `onChange`, so the
27
+ * person never sees two messages in two voices for one problem. `accept` and `maxSizeMb` still
28
+ * set the picker filter and the hint text.
22
29
  * @param {string} [props.error]
23
30
  * @param {string} [props.id]
24
31
  */
25
32
  export default function AppFileAttachment({ label, value, // File | { url, name } | array | null
26
- name, onChange, multiple, accept, maxSizeMb, optional, error, // external error, shown alongside internal validation errors
33
+ name, onChange, multiple, accept, maxSizeMb, optional, validate, error, // external error, shown alongside internal validation errors
27
34
  id, ...rest }: {
28
35
  label?: string;
29
36
  value?: File | {
@@ -39,6 +46,7 @@ id, ...rest }: {
39
46
  accept?: string;
40
47
  maxSizeMb?: number;
41
48
  optional?: boolean;
49
+ validate?: boolean;
42
50
  error?: string;
43
51
  id?: string;
44
52
  }): import("react").JSX.Element;
@@ -26,7 +26,6 @@ export { default as AppDateRangePicker } from "./components/AppDateRangePicker.j
26
26
  export { default as AppDescriptions } from "./components/AppDescriptions.jsx";
27
27
  export { default as AppDropdown } from "./components/AppDropdown.jsx";
28
28
  export { default as AppEmptyState } from "./components/AppEmptyState.jsx";
29
- export { default as AppFeedback } from "./components/AppFeedback.jsx";
30
29
  export { default as AppFileAttachment } from "./components/AppFileAttachment.jsx";
31
30
  export { default as AppFilePicker } from "./components/AppFilePicker.jsx";
32
31
  export { default as AppFloatingDock } from "./components/AppFloatingDock.jsx";
package/dist/ui-react.js CHANGED
@@ -2741,39 +2741,17 @@ var Qt = i(function({ icon: e, iconSize: t = 20, btnClassName: n = "topbar-icon-
2741
2741
  });
2742
2742
  });
2743
2743
  //#endregion
2744
- //#region src/components/AppFeedback.jsx
2745
- function $t({ onSubmit: e, surface: t, screen: n, heading: r = "Share feedback", label: i = "Feedback", placeholder: a, collectEmail: o = !1, position: s = "bottom-right", className: c = "", style: l, ...u }) {
2746
- U("AppFeedback", u);
2747
- let { setRef: d, innerRef: f } = Q({ on: { "wui-feedback-submit": (t) => {
2748
- let n = f.current;
2749
- n && Promise.resolve(e?.(t.detail)).then(() => n.submitted(), (e) => n.failed(typeof e?.userMessage == "string" ? e.userMessage : void 0));
2750
- } } });
2751
- return /* @__PURE__ */ E("wui-feedback", {
2752
- ref: d,
2753
- position: s,
2754
- label: i,
2755
- heading: r,
2756
- placeholder: a || void 0,
2757
- "collect-email": o ? "" : void 0,
2758
- surface: t || void 0,
2759
- screen: n || void 0,
2760
- class: c || void 0,
2761
- style: l,
2762
- ...u
2763
- });
2764
- }
2765
- //#endregion
2766
2744
  //#region src/lib/fileItem.js
2767
- function en(e) {
2745
+ function $t(e) {
2768
2746
  return e instanceof File ? `${e.name}:${e.size}` : e?.url || e?.name || "item";
2769
2747
  }
2770
- function tn(e) {
2748
+ function en(e) {
2771
2749
  return e instanceof File ? e.name : e?.name;
2772
2750
  }
2773
- function nn(e) {
2751
+ function tn(e) {
2774
2752
  return e instanceof File ? `${(e.size / 1024).toFixed(0)} KB` : null;
2775
2753
  }
2776
- function rn(e, t) {
2754
+ function nn(e, t) {
2777
2755
  let [n, r] = f(null);
2778
2756
  return o(() => {
2779
2757
  if (!t) {
@@ -2789,8 +2767,8 @@ function rn(e, t) {
2789
2767
  }
2790
2768
  //#endregion
2791
2769
  //#region src/lib/FileItemRow.jsx
2792
- function an({ item: e, isImage: t, onRemove: n, noun: r = "attachment" }) {
2793
- let i = rn(e, t), a = tn(e), o = nn(e);
2770
+ function rn({ item: e, isImage: t, onRemove: n, noun: r = "attachment" }) {
2771
+ let i = nn(e, t), a = en(e), o = tn(e);
2794
2772
  return /* @__PURE__ */ D("div", {
2795
2773
  className: "attach-item",
2796
2774
  children: [
@@ -2829,52 +2807,52 @@ function an({ item: e, isImage: t, onRemove: n, noun: r = "attachment" }) {
2829
2807
  }
2830
2808
  //#endregion
2831
2809
  //#region src/components/AppFileAttachment.jsx
2832
- function on({ label: e = "Attachment", value: t, name: n, onChange: r, multiple: i = !1, accept: a = k, maxSizeMb: o = A, optional: c = !1, error: l, id: u, ...d }) {
2833
- U("AppFileAttachment", d);
2834
- let p = s(), m = u || p, [h, g] = f(""), _ = i && Array.isArray(t) ? t : t ? [t] : [], v = F(a), y = (e) => e instanceof File ? P(e) : v || P(e), b = !i && _.length === 1 && y(_[0]);
2835
- function x(e) {
2810
+ function an({ label: e = "Attachment", value: t, name: n, onChange: r, multiple: i = !1, accept: a = k, maxSizeMb: o = A, optional: c = !1, validate: l = !0, error: u, id: d, ...p }) {
2811
+ U("AppFileAttachment", p);
2812
+ let m = s(), h = d || m, [g, _] = f(""), v = i && Array.isArray(t) ? t : t ? [t] : [], y = F(a), b = (e) => e instanceof File ? P(e) : y || P(e), x = !i && v.length === 1 && b(v[0]), S = o > 0, C = on(a, S ? o : 0);
2813
+ function w(e) {
2836
2814
  let n = Array.from(e.target.files || []);
2837
2815
  if (e.target.value = "", !n.length) return;
2838
2816
  let s = [], c = "";
2839
2817
  for (let e of n) {
2840
- let t = I(e, {
2818
+ let t = l ? I(e, {
2841
2819
  accept: a,
2842
- maxSizeMb: o
2843
- });
2820
+ maxSizeMb: S ? o : Infinity
2821
+ }) : null;
2844
2822
  if (t) {
2845
2823
  c ||= t;
2846
2824
  continue;
2847
2825
  }
2848
2826
  s.push(e);
2849
2827
  }
2850
- if (g(c), s.length) if (i) {
2851
- let e = Array.isArray(t) ? t : t ? [t] : [], n = new Set(e.map(en));
2852
- r(e.concat(s.filter((e) => !n.has(en(e)))));
2828
+ if (_(c), s.length) if (i) {
2829
+ let e = Array.isArray(t) ? t : t ? [t] : [], n = new Set(e.map($t));
2830
+ r(e.concat(s.filter((e) => !n.has($t(e)))));
2853
2831
  } else r(s[0]);
2854
2832
  }
2855
- function S(e) {
2856
- g(""), r(i ? _.filter((t, n) => n !== e) : null);
2833
+ function O(e) {
2834
+ _(""), r(i ? v.filter((t, n) => n !== e) : null);
2857
2835
  }
2858
- let C = l || h, w = C ? `${m}-error` : void 0, O = i || _.length === 0, M = v ? "image" : "file", N = i ? `Add ${M}s` : `Add ${v ? "an" : "a"} ${M}`;
2836
+ let j = u || g, M = j ? `${h}-error` : void 0, N = i || v.length === 0, L = y ? "image" : "file", R = i ? `Add ${L}s` : `Add ${y ? "an" : "a"} ${L}`;
2859
2837
  return /* @__PURE__ */ D("div", {
2860
2838
  className: "field",
2861
2839
  children: [
2862
2840
  /* @__PURE__ */ D("label", {
2863
2841
  className: "label",
2864
- htmlFor: m,
2842
+ htmlFor: h,
2865
2843
  children: [e, c && /* @__PURE__ */ E("span", {
2866
2844
  className: "label-optional",
2867
2845
  children: " (optional)"
2868
2846
  })]
2869
2847
  }),
2870
- O && /* @__PURE__ */ D(T, { children: [/* @__PURE__ */ D("label", {
2848
+ N && /* @__PURE__ */ D(T, { children: [/* @__PURE__ */ D("label", {
2871
2849
  className: "attach-drop",
2872
- htmlFor: m,
2850
+ htmlFor: h,
2873
2851
  children: [
2874
2852
  /* @__PURE__ */ E("span", {
2875
2853
  className: "attach-drop-icon",
2876
2854
  children: /* @__PURE__ */ E(Y, {
2877
- name: v ? "image" : "file-text",
2855
+ name: y ? "image" : "file-text",
2878
2856
  size: 18
2879
2857
  })
2880
2858
  }),
@@ -2882,15 +2860,10 @@ function on({ label: e = "Attachment", value: t, name: n, onChange: r, multiple:
2882
2860
  className: "attach-drop-copy",
2883
2861
  children: [/* @__PURE__ */ E("span", {
2884
2862
  className: "attach-drop-title",
2885
- children: N
2886
- }), /* @__PURE__ */ D("span", {
2863
+ children: R
2864
+ }), C && /* @__PURE__ */ E("span", {
2887
2865
  className: "attach-drop-hint",
2888
- children: [
2889
- j(a),
2890
- ", up to ",
2891
- o,
2892
- " MB"
2893
- ]
2866
+ children: C
2894
2867
  })]
2895
2868
  }),
2896
2869
  /* @__PURE__ */ E("span", {
@@ -2899,38 +2872,42 @@ function on({ label: e = "Attachment", value: t, name: n, onChange: r, multiple:
2899
2872
  })
2900
2873
  ]
2901
2874
  }), /* @__PURE__ */ E("input", {
2902
- id: m,
2875
+ id: h,
2903
2876
  type: "file",
2904
2877
  className: "visually-hidden",
2905
2878
  name: n,
2906
- accept: a,
2879
+ accept: a || void 0,
2907
2880
  multiple: i || void 0,
2908
- "aria-describedby": w,
2909
- onChange: x,
2910
- ...d
2881
+ "aria-describedby": M,
2882
+ onChange: w,
2883
+ ...p
2911
2884
  })] }),
2912
- b ? /* @__PURE__ */ E(sn, {
2913
- item: _[0],
2885
+ x ? /* @__PURE__ */ E(sn, {
2886
+ item: v[0],
2914
2887
  isImage: !0,
2915
- onRemove: () => S(0)
2916
- }) : _.length > 0 && /* @__PURE__ */ E("div", {
2888
+ onRemove: () => O(0)
2889
+ }) : v.length > 0 && /* @__PURE__ */ E("div", {
2917
2890
  className: "attach-list",
2918
- children: _.map((e, t) => /* @__PURE__ */ E(an, {
2891
+ children: v.map((e, t) => /* @__PURE__ */ E(rn, {
2919
2892
  item: e,
2920
- isImage: y(e),
2921
- onRemove: () => S(t)
2922
- }, en(e)))
2893
+ isImage: b(e),
2894
+ onRemove: () => O(t)
2895
+ }, $t(e)))
2923
2896
  }),
2924
- C && /* @__PURE__ */ E("div", {
2897
+ j && /* @__PURE__ */ E("div", {
2925
2898
  className: "field-error",
2926
- id: `${m}-error`,
2927
- children: C
2899
+ id: `${h}-error`,
2900
+ children: j
2928
2901
  })
2929
2902
  ]
2930
2903
  });
2931
2904
  }
2905
+ function on(e, t) {
2906
+ let n = e?.trim() ? j(e) : "", r = t > 0 ? `up to ${t} MB` : "";
2907
+ return n && r ? `${n}, ${r}` : r ? `Up to ${t} MB` : n;
2908
+ }
2932
2909
  function sn({ item: e, isImage: t, onRemove: n }) {
2933
- let r = rn(e, t), i = tn(e), a = nn(e);
2910
+ let r = nn(e, t), i = en(e), a = tn(e);
2934
2911
  return /* @__PURE__ */ D("div", {
2935
2912
  className: "attach-preview",
2936
2913
  children: [/* @__PURE__ */ D("div", {
@@ -2981,7 +2958,7 @@ function cn({ label: e, value: t, name: n, id: r, onPick: i, multiple: a = !1, m
2981
2958
  }, ce = (e) => {
2982
2959
  let n = Array.from(e || []);
2983
2960
  if (!n.length) return;
2984
- let r = Array.isArray(t) ? t : t ? [t] : [], a = new Set(r.map(en)), o = "", s = [];
2961
+ let r = Array.isArray(t) ? t : t ? [t] : [], a = new Set(r.map($t)), o = "", s = [];
2985
2962
  for (let e of n) {
2986
2963
  let t = I(e, {
2987
2964
  accept: l,
@@ -2991,7 +2968,7 @@ function cn({ label: e, value: t, name: n, id: r, onPick: i, multiple: a = !1, m
2991
2968
  o ||= t;
2992
2969
  continue;
2993
2970
  }
2994
- a.has(en(e)) || (a.add(en(e)), s.push(e));
2971
+ a.has($t(e)) || (a.add($t(e)), s.push(e));
2995
2972
  }
2996
2973
  let d = r.concat(s);
2997
2974
  c && d.length > c && (d = d.slice(0, c), o ||= `Up to ${c} files.`), O(o), i(d);
@@ -3141,12 +3118,12 @@ function cn({ label: e, value: t, name: n, id: r, onPick: i, multiple: a = !1, m
3141
3118
  fe,
3142
3119
  a && L.length > 0 && /* @__PURE__ */ E("div", {
3143
3120
  className: "attach-list",
3144
- children: L.map((e, t) => /* @__PURE__ */ E(an, {
3121
+ children: L.map((e, t) => /* @__PURE__ */ E(rn, {
3145
3122
  item: e,
3146
3123
  isImage: e instanceof File ? P(e) : V || P(e),
3147
3124
  noun: "file",
3148
3125
  onRemove: () => ue(t)
3149
- }, en(e)))
3126
+ }, $t(e)))
3150
3127
  })
3151
3128
  ]
3152
3129
  }),
@@ -5999,4 +5976,4 @@ function Yr(e, t = 10) {
5999
5976
  };
6000
5977
  }
6001
5978
  //#endregion
6002
- export { Oe as AppAccordion, ke as AppActionIcon, Me as AppAlert, ze as AppAsyncBlock, Ze as AppAutocomplete, rt as AppAvatar, ot as AppAvatarGroup, st as AppBadge, lt as AppBanner, ut as AppBreadcrumbs, Ie as AppButton, ft as AppCallout, mt as AppCard, gt as AppCheckbox, _t as AppChip, vt as AppChoiceCard, yt as AppChoiceChip, bt as AppColorField, St as AppCompareTable, jt as AppConfirmDialog, Nt as AppConsentBanner, Ft as AppCopyButton, Gt as AppDataTable, Kt as AppDatePicker, qt as AppDateRangePicker, Jt as AppDescriptions, Zt as AppDropdown, Le as AppEmptyState, $t as AppFeedback, on as AppFileAttachment, cn as AppFilePicker, ln as AppFloatingDock, un as AppFormActions, dn as AppFormRow, fn as AppFormSection, Y as AppIcon, pn as AppInfoList, He as AppInfoTip, Ct as AppInput, vn as AppKpiTile, Sn as AppLink, wn as AppLogoPicker, On as AppMeter, Ot as AppModal, kn as AppMultiSelect, An as AppNumberInput, jn as AppOtpInput, Mn as AppPageHeader, Nn as AppPagination, Pn as AppPhoneNumberInput, Ve as AppPopover, Fn as AppPricingCard, Rn as AppProgress, zn as AppRadio, Bn as AppRepeater, Z as AppRequiredMark, Vn as AppResourceCard, Un as AppResult, Wn as AppScrollbar, Gn as AppSearch, Kn as AppSegmented, Jn as AppSelect, Bt as AppSelectMini, Yn as AppShell, Qn as AppSidebarMenu, It as AppSkeleton, Lt as AppSkeletonRows, $n as AppSlider, Re as AppSpinner, tr as AppSplash, nr as AppStatusBadge, rr as AppStepper, ar as AppSwitch, or as AppTableEmptyState, Ht as AppTablePagination, ur as AppTabs, dr as AppTagInput, fr as AppTextarea, hr as AppTimePicker, mr as AppTimeline, Fr as AppToast, Lr as AppToolbar, G as AppTooltip, Rr as AppWizard, Br as AppWorkspaceSwitcher, At as MODAL_ICONS, Gr as dismissAll, Jr as errorToast, Te as iconNames, De as registerIcons, qr as toast, Yr as usePagination };
5979
+ export { Oe as AppAccordion, ke as AppActionIcon, Me as AppAlert, ze as AppAsyncBlock, Ze as AppAutocomplete, rt as AppAvatar, ot as AppAvatarGroup, st as AppBadge, lt as AppBanner, ut as AppBreadcrumbs, Ie as AppButton, ft as AppCallout, mt as AppCard, gt as AppCheckbox, _t as AppChip, vt as AppChoiceCard, yt as AppChoiceChip, bt as AppColorField, St as AppCompareTable, jt as AppConfirmDialog, Nt as AppConsentBanner, Ft as AppCopyButton, Gt as AppDataTable, Kt as AppDatePicker, qt as AppDateRangePicker, Jt as AppDescriptions, Zt as AppDropdown, Le as AppEmptyState, an as AppFileAttachment, cn as AppFilePicker, ln as AppFloatingDock, un as AppFormActions, dn as AppFormRow, fn as AppFormSection, Y as AppIcon, pn as AppInfoList, He as AppInfoTip, Ct as AppInput, vn as AppKpiTile, Sn as AppLink, wn as AppLogoPicker, On as AppMeter, Ot as AppModal, kn as AppMultiSelect, An as AppNumberInput, jn as AppOtpInput, Mn as AppPageHeader, Nn as AppPagination, Pn as AppPhoneNumberInput, Ve as AppPopover, Fn as AppPricingCard, Rn as AppProgress, zn as AppRadio, Bn as AppRepeater, Z as AppRequiredMark, Vn as AppResourceCard, Un as AppResult, Wn as AppScrollbar, Gn as AppSearch, Kn as AppSegmented, Jn as AppSelect, Bt as AppSelectMini, Yn as AppShell, Qn as AppSidebarMenu, It as AppSkeleton, Lt as AppSkeletonRows, $n as AppSlider, Re as AppSpinner, tr as AppSplash, nr as AppStatusBadge, rr as AppStepper, ar as AppSwitch, or as AppTableEmptyState, Ht as AppTablePagination, ur as AppTabs, dr as AppTagInput, fr as AppTextarea, hr as AppTimePicker, mr as AppTimeline, Fr as AppToast, Lr as AppToolbar, G as AppTooltip, Rr as AppWizard, Br as AppWorkspaceSwitcher, At as MODAL_ICONS, Gr as dismissAll, Jr as errorToast, Te as iconNames, De as registerIcons, qr as toast, Yr as usePagination };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webority/ui-react",
3
- "version": "0.13.1",
3
+ "version": "0.13.4",
4
4
  "description": "Webority shared React component library — App* primitives on react-bootstrap + the @webority/theme design system.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "module",
@@ -28,8 +28,8 @@
28
28
  },
29
29
  "sideEffects": false,
30
30
  "dependencies": {
31
- "@webority/theme": "0.13.1",
32
- "@webority/ui-elements": "0.13.1"
31
+ "@webority/theme": "0.13.4",
32
+ "@webority/ui-elements": "0.13.4"
33
33
  },
34
34
  "peerDependencies": {
35
35
  "@webority/analytics": "^0.5.2",
@@ -1,61 +0,0 @@
1
- import "@webority/ui-elements";
2
- /**
3
- * An in-product feedback affordance — a floating trigger pinned to a page corner that opens a
4
- * small panel with a message box and, optionally, an email address.
5
- *
6
- * Wraps the shared `<wui-feedback>` element, which owns the panel, the keyboard and ARIA
7
- * behaviour, and the busy/error/thank-you states. This wrapper owns exactly one thing: turning
8
- * the element's `wui-feedback-submit` event into your `onSubmit`, and your promise's outcome
9
- * back into the element's `submitted()` / `failed()`.
10
- *
11
- * `onSubmit` is REQUIRED and it is the whole contract — resolve and the person sees a
12
- * thank-you, reject and they see an inline error with everything they typed still there. The
13
- * library never posts anything itself: every product has its own endpoint, its own auth and its
14
- * own idea of where feedback lands.
15
- *
16
- * ```jsx
17
- * <AppFeedback
18
- * surface="customer-portal"
19
- * screen={location.pathname}
20
- * collectEmail
21
- * onSubmit={async ({ message, email, surface, screen }) => {
22
- * await Api.Feedback.submit({ message, email, surface, screen });
23
- * }}
24
- * />
25
- * ```
26
- *
27
- * To show your own failure copy rather than the element's default, reject with an error
28
- * carrying a `userMessage` — an exception's own `message` is never shown, because it is written
29
- * for a developer, not for the person reading it.
30
- *
31
- * @param {object} props
32
- * @param {(payload: { message: string, email: string, surface: string, screen: string }) =>
33
- * Promise<void>|void} props.onSubmit Required. Deliver the feedback; resolve on success,
34
- * reject on failure.
35
- * @param {string} [props.surface] Which product surface this came from, passed through to onSubmit.
36
- * @param {string} [props.screen] Which screen/route it came from, passed through to onSubmit.
37
- * @param {string} [props.heading='Share feedback'] Panel heading, and the dialog's accessible name.
38
- * @param {string} [props.label='Feedback'] Trigger text beside the icon.
39
- * @param {string} [props.placeholder] Placeholder for the message box.
40
- * @param {boolean} [props.collectEmail=false] Also ask for an email address.
41
- * @param {"bottom-right"|"bottom-left"} [props.position='bottom-right'] Which corner it pins to.
42
- * @param {string} [props.className] Extra classes on the element.
43
- * @param {import('react').CSSProperties} [props.style] Inline style; lands on the element with `className`.
44
- */
45
- export default function AppFeedback({ onSubmit, surface, screen, heading, label, placeholder, collectEmail, position, className, style, ...rest }: {
46
- onSubmit: (payload: {
47
- message: string;
48
- email: string;
49
- surface: string;
50
- screen: string;
51
- }) => Promise<void> | void;
52
- surface?: string;
53
- screen?: string;
54
- heading?: string;
55
- label?: string;
56
- placeholder?: string;
57
- collectEmail?: boolean;
58
- position?: "bottom-right" | "bottom-left";
59
- className?: string;
60
- style?: import('react').CSSProperties;
61
- }): import("react").JSX.Element;