@jobber/components 8.11.1 → 8.12.1

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.
@@ -726,22 +726,29 @@ function InputNumberExperimentalInputCompound(props = {}) {
726
726
  var _a;
727
727
  const ctx = useInputNumberExperimentalContext("Input");
728
728
  const labelText = (_a = props.placeholder) !== null && _a !== void 0 ? _a : ctx.placeholder;
729
- return (React.createElement("div", { className: classnames(styles.inputWrapper, !ctx.showMiniLabel && styles.hideLabel, ctx.size !== "default" && styles[ctx.size], ctx.disabled && styles.disabled) },
729
+ const rootProps = useRenderElement.mergeProps({
730
+ className: classnames(styles.inputWrapper, !ctx.showMiniLabel && styles.hideLabel, ctx.size !== "default" && styles[ctx.size], ctx.disabled && styles.disabled),
731
+ }, { className: props.className, style: props.style });
732
+ return (React.createElement("div", Object.assign({}, rootProps),
730
733
  React.createElement(NumberFieldInput.NumberFieldInput, { "aria-busy": ctx.loading || undefined, autoComplete: resolveAutocomplete(ctx.autocomplete), className: styles.input, inputMode: ctx.keyboard, maxLength: ctx.maxLength, onBlur: ctx.onBlur, onFocus: ctx.onFocus, onKeyDown: ctx.onKeyDown, onKeyUp: ctx.onKeyUp, placeholder: " ", ref: ctx.innerInputRef }),
731
734
  labelText && (React.createElement("label", { className: styles.label, htmlFor: ctx.id }, labelText)),
732
735
  ctx.loading ? (React.createElement("div", { className: styles.loadingIndicator },
733
736
  React.createElement(ActivityIndicator.ActivityIndicator, { size: "small" }))) : (!ctx.compoundLayout && React.createElement(InputNumberExperimentalStepperCompound, null))));
734
737
  }
735
- function InputNumberExperimentalAffixCompound({ variation, label, icon, onClick, ariaLabel, }) {
738
+ function InputNumberExperimentalAffixCompound({ variation, label, icon, onClick, ariaLabel, children, className, style, }) {
736
739
  const ctx = useInputNumberExperimentalContext("Affix");
737
- if (!icon && !label) {
740
+ if (!icon && !label && !children) {
738
741
  return null;
739
742
  }
740
- return (React.createElement("div", { className: classnames(styles.compoundAffix, variation === "suffix" && styles.suffix) },
743
+ const rootProps = useRenderElement.mergeProps({
744
+ className: classnames(styles.compoundAffix, variation === "suffix" && styles.suffix),
745
+ }, { className, style });
746
+ return (React.createElement("div", Object.assign({}, rootProps),
741
747
  icon && (React.createElement(AffixIconContent, { icon: icon, size: ctx.size, onClick: onClick, ariaLabel: ariaLabel })),
742
- label && React.createElement("span", { className: styles.affixLabelText }, label)));
748
+ label && React.createElement("span", { className: styles.affixLabelText }, label),
749
+ children));
743
750
  }
744
- function InputNumberExperimentalStepperCompound({ incrementLabel, decrementLabel, } = {}) {
751
+ function InputNumberExperimentalStepperCompound({ incrementLabel, decrementLabel, className, style, } = {}) {
745
752
  var _a;
746
753
  const ctx = useInputNumberExperimentalContext("Stepper");
747
754
  // Hidden while loading; the loading indicator renders in the input wrapper
@@ -752,7 +759,8 @@ function InputNumberExperimentalStepperCompound({ incrementLabel, decrementLabel
752
759
  const labelTarget = (_a = ctx.placeholder) !== null && _a !== void 0 ? _a : "value";
753
760
  const resolvedIncrementLabel = incrementLabel !== null && incrementLabel !== void 0 ? incrementLabel : `Increase ${labelTarget}`;
754
761
  const resolvedDecrementLabel = decrementLabel !== null && decrementLabel !== void 0 ? decrementLabel : `Decrease ${labelTarget}`;
755
- return (React.createElement("div", { className: styles.stepper },
762
+ const rootProps = useRenderElement.mergeProps({ className: styles.stepper }, { className, style });
763
+ return (React.createElement("div", Object.assign({}, rootProps),
756
764
  React.createElement(NumberFieldInput.NumberFieldIncrement, { "aria-label": resolvedIncrementLabel, className: styles.stepperButton }, "\u25B2"),
757
765
  React.createElement(NumberFieldInput.NumberFieldDecrement, { "aria-label": resolvedDecrementLabel, className: styles.stepperButton }, "\u25BC")));
758
766
  }
@@ -706,22 +706,29 @@ function InputNumberExperimentalInputCompound(props = {}) {
706
706
  var _a;
707
707
  const ctx = useInputNumberExperimentalContext("Input");
708
708
  const labelText = (_a = props.placeholder) !== null && _a !== void 0 ? _a : ctx.placeholder;
709
- return (React__default.createElement("div", { className: classnames(styles.inputWrapper, !ctx.showMiniLabel && styles.hideLabel, ctx.size !== "default" && styles[ctx.size], ctx.disabled && styles.disabled) },
709
+ const rootProps = mergeProps({
710
+ className: classnames(styles.inputWrapper, !ctx.showMiniLabel && styles.hideLabel, ctx.size !== "default" && styles[ctx.size], ctx.disabled && styles.disabled),
711
+ }, { className: props.className, style: props.style });
712
+ return (React__default.createElement("div", Object.assign({}, rootProps),
710
713
  React__default.createElement(NumberFieldInput, { "aria-busy": ctx.loading || undefined, autoComplete: resolveAutocomplete(ctx.autocomplete), className: styles.input, inputMode: ctx.keyboard, maxLength: ctx.maxLength, onBlur: ctx.onBlur, onFocus: ctx.onFocus, onKeyDown: ctx.onKeyDown, onKeyUp: ctx.onKeyUp, placeholder: " ", ref: ctx.innerInputRef }),
711
714
  labelText && (React__default.createElement("label", { className: styles.label, htmlFor: ctx.id }, labelText)),
712
715
  ctx.loading ? (React__default.createElement("div", { className: styles.loadingIndicator },
713
716
  React__default.createElement(ActivityIndicator, { size: "small" }))) : (!ctx.compoundLayout && React__default.createElement(InputNumberExperimentalStepperCompound, null))));
714
717
  }
715
- function InputNumberExperimentalAffixCompound({ variation, label, icon, onClick, ariaLabel, }) {
718
+ function InputNumberExperimentalAffixCompound({ variation, label, icon, onClick, ariaLabel, children, className, style, }) {
716
719
  const ctx = useInputNumberExperimentalContext("Affix");
717
- if (!icon && !label) {
720
+ if (!icon && !label && !children) {
718
721
  return null;
719
722
  }
720
- return (React__default.createElement("div", { className: classnames(styles.compoundAffix, variation === "suffix" && styles.suffix) },
723
+ const rootProps = mergeProps({
724
+ className: classnames(styles.compoundAffix, variation === "suffix" && styles.suffix),
725
+ }, { className, style });
726
+ return (React__default.createElement("div", Object.assign({}, rootProps),
721
727
  icon && (React__default.createElement(AffixIconContent, { icon: icon, size: ctx.size, onClick: onClick, ariaLabel: ariaLabel })),
722
- label && React__default.createElement("span", { className: styles.affixLabelText }, label)));
728
+ label && React__default.createElement("span", { className: styles.affixLabelText }, label),
729
+ children));
723
730
  }
724
- function InputNumberExperimentalStepperCompound({ incrementLabel, decrementLabel, } = {}) {
731
+ function InputNumberExperimentalStepperCompound({ incrementLabel, decrementLabel, className, style, } = {}) {
725
732
  var _a;
726
733
  const ctx = useInputNumberExperimentalContext("Stepper");
727
734
  // Hidden while loading; the loading indicator renders in the input wrapper
@@ -732,7 +739,8 @@ function InputNumberExperimentalStepperCompound({ incrementLabel, decrementLabel
732
739
  const labelTarget = (_a = ctx.placeholder) !== null && _a !== void 0 ? _a : "value";
733
740
  const resolvedIncrementLabel = incrementLabel !== null && incrementLabel !== void 0 ? incrementLabel : `Increase ${labelTarget}`;
734
741
  const resolvedDecrementLabel = decrementLabel !== null && decrementLabel !== void 0 ? decrementLabel : `Decrease ${labelTarget}`;
735
- return (React__default.createElement("div", { className: styles.stepper },
742
+ const rootProps = mergeProps({ className: styles.stepper }, { className, style });
743
+ return (React__default.createElement("div", Object.assign({}, rootProps),
736
744
  React__default.createElement(NumberFieldIncrement, { "aria-label": resolvedIncrementLabel, className: styles.stepperButton }, "\u25B2"),
737
745
  React__default.createElement(NumberFieldDecrement, { "aria-label": resolvedDecrementLabel, className: styles.stepperButton }, "\u25BC")));
738
746
  }
@@ -128,7 +128,7 @@ function SideDrawer({ children, onRequestClose, open, variation = "base", scroll
128
128
  }, style: UNSAFE_style === null || UNSAFE_style === void 0 ? void 0 : UNSAFE_style.container },
129
129
  React.createElement("div", { ref: sideDrawerRef, role: "dialog", className: classnames(styles.container, styles.hasShadow, {
130
130
  [styles.subtle]: variation === "subtle",
131
- }), tabIndex: 0, onKeyUp: handleKeyUp },
131
+ }), tabIndex: 0, onKeyDown: handleKeyDown },
132
132
  React.createElement("div", { className: classnames(styles.header, {
133
133
  [styles.hasShadow]: headerShadowRef.current && !noHeaderShadow,
134
134
  }) },
@@ -153,8 +153,9 @@ function SideDrawer({ children, onRequestClose, open, variation = "base", scroll
153
153
  return SideDrawerRender;
154
154
  }
155
155
  return ReactDOM.createPortal(SideDrawerRender, container);
156
- function handleKeyUp(event) {
156
+ function handleKeyDown(event) {
157
157
  if (event.key === "Escape") {
158
+ event.stopPropagation();
158
159
  onRequestClose();
159
160
  }
160
161
  }
@@ -126,7 +126,7 @@ function SideDrawer({ children, onRequestClose, open, variation = "base", scroll
126
126
  }, style: UNSAFE_style === null || UNSAFE_style === void 0 ? void 0 : UNSAFE_style.container },
127
127
  React__default.createElement("div", { ref: sideDrawerRef, role: "dialog", className: classnames(styles.container, styles.hasShadow, {
128
128
  [styles.subtle]: variation === "subtle",
129
- }), tabIndex: 0, onKeyUp: handleKeyUp },
129
+ }), tabIndex: 0, onKeyDown: handleKeyDown },
130
130
  React__default.createElement("div", { className: classnames(styles.header, {
131
131
  [styles.hasShadow]: headerShadowRef.current && !noHeaderShadow,
132
132
  }) },
@@ -151,8 +151,9 @@ function SideDrawer({ children, onRequestClose, open, variation = "base", scroll
151
151
  return SideDrawerRender;
152
152
  }
153
153
  return createPortal(SideDrawerRender, container);
154
- function handleKeyUp(event) {
154
+ function handleKeyDown(event) {
155
155
  if (event.key === "Escape") {
156
+ event.stopPropagation();
156
157
  onRequestClose();
157
158
  }
158
159
  }
@@ -64,18 +64,29 @@ function isSafari(userAgent) {
64
64
  return getClientBrowser(userAgent) === "Apple Safari";
65
65
  }
66
66
 
67
+ // Allowlist rather than denylist so unrecognized types fail safe (fall back to
68
+ // a non-image preview) instead of handing a broken file to an <img>.
69
+ const PREVIEWABLE_TYPES = new Set([
70
+ "image/jpeg",
71
+ "image/jpg",
72
+ "image/png",
73
+ "image/gif",
74
+ "image/webp",
75
+ "image/bmp",
76
+ "image/avif",
77
+ ]);
78
+ const SAFARI_ONLY_TYPES = new Set(["image/heic", "image/heif"]);
67
79
  function isPreviewableImage(type) {
68
- if (!type || !type.startsWith("image/"))
80
+ if (!type)
69
81
  return false;
70
- const userAgent = typeof document === "undefined" ? "" : window.navigator.userAgent;
71
- const isHeic = type.startsWith("image/heic");
72
- const isSVG = type.startsWith("image/svg");
73
- const isVendor = /^image\/(vnd[.-]|x-)/i.test(type);
74
- if (isSVG || isVendor)
75
- return false;
76
- if (isHeic && !isSafari(userAgent))
77
- return false;
78
- return true;
82
+ const normalizedType = type.toLowerCase();
83
+ if (PREVIEWABLE_TYPES.has(normalizedType))
84
+ return true;
85
+ if (SAFARI_ONLY_TYPES.has(normalizedType)) {
86
+ const userAgent = typeof document === "undefined" ? "" : window.navigator.userAgent;
87
+ return isSafari(userAgent);
88
+ }
89
+ return false;
79
90
  }
80
91
 
81
92
  function Thumbnail({ compact = false, size, file, UNSAFE_className, UNSAFE_style, }) {
@@ -62,18 +62,29 @@ function isSafari(userAgent) {
62
62
  return getClientBrowser(userAgent) === "Apple Safari";
63
63
  }
64
64
 
65
+ // Allowlist rather than denylist so unrecognized types fail safe (fall back to
66
+ // a non-image preview) instead of handing a broken file to an <img>.
67
+ const PREVIEWABLE_TYPES = new Set([
68
+ "image/jpeg",
69
+ "image/jpg",
70
+ "image/png",
71
+ "image/gif",
72
+ "image/webp",
73
+ "image/bmp",
74
+ "image/avif",
75
+ ]);
76
+ const SAFARI_ONLY_TYPES = new Set(["image/heic", "image/heif"]);
65
77
  function isPreviewableImage(type) {
66
- if (!type || !type.startsWith("image/"))
78
+ if (!type)
67
79
  return false;
68
- const userAgent = typeof document === "undefined" ? "" : window.navigator.userAgent;
69
- const isHeic = type.startsWith("image/heic");
70
- const isSVG = type.startsWith("image/svg");
71
- const isVendor = /^image\/(vnd[.-]|x-)/i.test(type);
72
- if (isSVG || isVendor)
73
- return false;
74
- if (isHeic && !isSafari(userAgent))
75
- return false;
76
- return true;
80
+ const normalizedType = type.toLowerCase();
81
+ if (PREVIEWABLE_TYPES.has(normalizedType))
82
+ return true;
83
+ if (SAFARI_ONLY_TYPES.has(normalizedType)) {
84
+ const userAgent = typeof document === "undefined" ? "" : window.navigator.userAgent;
85
+ return isSafari(userAgent);
86
+ }
87
+ return false;
77
88
  }
78
89
 
79
90
  function Thumbnail({ compact = false, size, file, UNSAFE_className, UNSAFE_style, }) {
@@ -4,11 +4,11 @@ declare function InputNumberExperimentalInputCompound(props?: InputNumberExperim
4
4
  declare namespace InputNumberExperimentalInputCompound {
5
5
  var displayName: string;
6
6
  }
7
- declare function InputNumberExperimentalAffixCompound({ variation, label, icon, onClick, ariaLabel, }: InputNumberExperimentalAffixCompoundProps): React.JSX.Element | null;
7
+ declare function InputNumberExperimentalAffixCompound({ variation, label, icon, onClick, ariaLabel, children, className, style, }: InputNumberExperimentalAffixCompoundProps): React.JSX.Element | null;
8
8
  declare namespace InputNumberExperimentalAffixCompound {
9
9
  var displayName: string;
10
10
  }
11
- declare function InputNumberExperimentalStepperCompound({ incrementLabel, decrementLabel, }?: InputNumberExperimentalStepperCompoundProps): React.JSX.Element | null;
11
+ declare function InputNumberExperimentalStepperCompound({ incrementLabel, decrementLabel, className, style, }?: InputNumberExperimentalStepperCompoundProps): React.JSX.Element | null;
12
12
  declare namespace InputNumberExperimentalStepperCompound {
13
13
  var displayName: string;
14
14
  }
@@ -1,5 +1,13 @@
1
- import type { FocusEvent, KeyboardEvent, ReactNode } from "react";
1
+ import type { CSSProperties, FocusEvent, KeyboardEvent, ReactNode } from "react";
2
2
  import type { IconNames } from "../../Icon";
3
+ /**
4
+ * `className`/`style` shared by every `InputNumberExperimental` building block.
5
+ * Both compose with the block's internal styling rather than replacing it.
6
+ */
7
+ export interface InputNumberExperimentalStyleProps {
8
+ readonly className?: string;
9
+ readonly style?: CSSProperties;
10
+ }
3
11
  /**
4
12
  * Affix descriptor used by the `prefix` and `suffix` props on
5
13
  * `<InputNumberExperimental>` for the default (drop-in) render.
@@ -118,26 +126,30 @@ export interface InputNumberExperimentalRef {
118
126
  blur(): void;
119
127
  focus(): void;
120
128
  }
121
- export interface InputNumberExperimentalInputProps {
129
+ export interface InputNumberExperimentalInputProps extends InputNumberExperimentalStyleProps {
122
130
  /**
123
131
  * Overrides the floating mini-label text. Falls back to the root component's
124
132
  * `placeholder` prop when omitted.
125
133
  */
126
134
  readonly placeholder?: string;
127
135
  }
128
- export interface InputNumberExperimentalAffixCompound {
136
+ export interface InputNumberExperimentalAffixCompound extends InputNumberExperimentalStyleProps {
129
137
  readonly variation: "prefix" | "suffix";
130
138
  readonly label?: string;
131
139
  readonly icon?: IconNames;
132
140
  readonly ariaLabel?: never;
133
141
  readonly onClick?: never;
142
+ /** Arbitrary affix content, beyond the built-in `label`/`icon`. */
143
+ readonly children?: ReactNode;
134
144
  }
135
- export interface InputNumberExperimentalAffixCompoundClickable {
145
+ export interface InputNumberExperimentalAffixCompoundClickable extends InputNumberExperimentalStyleProps {
136
146
  readonly variation: "prefix" | "suffix";
137
147
  readonly label?: string;
138
148
  readonly icon: IconNames;
139
149
  readonly ariaLabel: string;
140
150
  onClick(): void;
151
+ /** Arbitrary affix content, beyond the built-in `label`/`icon`. */
152
+ readonly children?: ReactNode;
141
153
  }
142
154
  /**
143
155
  * Compound `.Affix` props. Discriminated by whether `onClick` is set:
@@ -149,7 +161,7 @@ export interface InputNumberExperimentalAffixCompoundClickable {
149
161
  * back to the default API when you need that.
150
162
  */
151
163
  export type InputNumberExperimentalAffixCompoundProps = InputNumberExperimentalAffixCompound | InputNumberExperimentalAffixCompoundClickable;
152
- export interface InputNumberExperimentalStepperCompoundProps {
164
+ export interface InputNumberExperimentalStepperCompoundProps extends InputNumberExperimentalStyleProps {
153
165
  /**
154
166
  * Override the increment button's accessible label.
155
167
  * Defaults to `Increase ${placeholder ?? "value"}`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jobber/components",
3
- "version": "8.11.1",
3
+ "version": "8.12.1",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -556,5 +556,5 @@
556
556
  "> 1%",
557
557
  "IE 10"
558
558
  ],
559
- "gitHead": "85613843d134dfa6dee673b87293f5e0ceb3bfa5"
559
+ "gitHead": "80813476ca22f110f6cc3a8bb1838279cd5dac3d"
560
560
  }