@bspk/ui 1.3.9 → 1.3.10

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 (129) hide show
  1. package/dist/components/BannerAlert/BannerAlert.d.ts +5 -5
  2. package/dist/components/BannerAlert/BannerAlert.js +5 -5
  3. package/dist/components/Breadcrumb/BreadcrumbDropdown.d.ts +6 -0
  4. package/dist/components/Breadcrumb/BreadcrumbDropdown.js +6 -0
  5. package/dist/components/Breadcrumb/BreadcrumbDropdown.js.map +1 -1
  6. package/dist/components/CheckboxGroup/CheckboxGroupExample.js +1 -0
  7. package/dist/components/CheckboxGroup/CheckboxGroupExample.js.map +1 -1
  8. package/dist/components/Drawer/Drawer.js.map +1 -1
  9. package/dist/components/Field/FieldDescription.d.ts +7 -5
  10. package/dist/components/Field/FieldDescription.js +7 -3
  11. package/dist/components/Field/FieldDescription.js.map +1 -1
  12. package/dist/components/Field/FieldError.d.ts +6 -0
  13. package/dist/components/Field/FieldError.js +6 -0
  14. package/dist/components/Field/FieldError.js.map +1 -1
  15. package/dist/components/Field/FieldLabel.d.ts +6 -0
  16. package/dist/components/Field/FieldLabel.js +6 -0
  17. package/dist/components/Field/FieldLabel.js.map +1 -1
  18. package/dist/components/Field/utils.d.ts +5 -0
  19. package/dist/components/Field/utils.js +5 -0
  20. package/dist/components/Field/utils.js.map +1 -1
  21. package/dist/components/InlineAlert/SvgWarningTwoTone.d.ts +6 -0
  22. package/dist/components/InlineAlert/SvgWarningTwoTone.js +6 -0
  23. package/dist/components/InlineAlert/SvgWarningTwoTone.js.map +1 -1
  24. package/dist/components/InputNumber/IncrementButton.d.ts +13 -3
  25. package/dist/components/InputNumber/IncrementButton.js +11 -4
  26. package/dist/components/InputNumber/IncrementButton.js.map +1 -1
  27. package/dist/components/InputNumber/InputNumber.js +26 -10
  28. package/dist/components/InputNumber/InputNumber.js.map +1 -1
  29. package/dist/components/InputNumber/InputNumberExample.js +1 -0
  30. package/dist/components/InputNumber/InputNumberExample.js.map +1 -1
  31. package/dist/components/InputNumber/input-number.css +6 -0
  32. package/dist/components/InputNumber/input-number.css.js +6 -0
  33. package/dist/components/Link/Link.d.ts +1 -1
  34. package/dist/components/Link/Link.js +1 -1
  35. package/dist/components/OTPInput/OTPInput.d.ts +5 -1
  36. package/dist/components/OTPInput/OTPInput.js +5 -1
  37. package/dist/components/OTPInput/OTPInput.js.map +1 -1
  38. package/dist/components/Pagination/PageList.d.ts +6 -0
  39. package/dist/components/Pagination/PageList.js +6 -0
  40. package/dist/components/Pagination/PageList.js.map +1 -1
  41. package/dist/components/Scrim/Scrim.d.ts +0 -1
  42. package/dist/components/Scrim/Scrim.js +0 -1
  43. package/dist/components/Scrim/Scrim.js.map +1 -1
  44. package/dist/components/Select/Select.d.ts +11 -11
  45. package/dist/components/Select/Select.js +11 -11
  46. package/dist/components/Skeleton/Circular.d.ts +6 -0
  47. package/dist/components/Skeleton/Circular.js +6 -0
  48. package/dist/components/Skeleton/Circular.js.map +1 -1
  49. package/dist/components/Skeleton/Photo.d.ts +6 -0
  50. package/dist/components/Skeleton/Photo.js +6 -0
  51. package/dist/components/Skeleton/Photo.js.map +1 -1
  52. package/dist/components/Skeleton/Profile.d.ts +6 -0
  53. package/dist/components/Skeleton/Profile.js +6 -0
  54. package/dist/components/Skeleton/Profile.js.map +1 -1
  55. package/dist/components/Skeleton/Rectangular.d.ts +6 -0
  56. package/dist/components/Skeleton/Rectangular.js +6 -0
  57. package/dist/components/Skeleton/Rectangular.js.map +1 -1
  58. package/dist/components/Skeleton/Thumbnail.d.ts +6 -0
  59. package/dist/components/Skeleton/Thumbnail.js +6 -0
  60. package/dist/components/Skeleton/Thumbnail.js.map +1 -1
  61. package/dist/components/Slider/SliderIntervalDots.d.ts +6 -0
  62. package/dist/components/Slider/SliderIntervalDots.js +6 -0
  63. package/dist/components/Slider/SliderIntervalDots.js.map +1 -1
  64. package/dist/components/Snackbar/Manager.d.ts +0 -1
  65. package/dist/components/Snackbar/Manager.js +0 -1
  66. package/dist/components/Snackbar/Manager.js.map +1 -1
  67. package/dist/components/Snackbar/Snackbar.d.ts +0 -1
  68. package/dist/components/Snackbar/Snackbar.js +0 -1
  69. package/dist/components/Snackbar/Snackbar.js.map +1 -1
  70. package/dist/components/TabList/TabList.js +1 -2
  71. package/dist/components/TabList/TabList.js.map +1 -1
  72. package/dist/components/Table/Footer.d.ts +6 -0
  73. package/dist/components/Table/Footer.js +6 -0
  74. package/dist/components/Table/Footer.js.map +1 -1
  75. package/dist/components/TimePicker/Listbox.d.ts +6 -0
  76. package/dist/components/TimePicker/Listbox.js +6 -0
  77. package/dist/components/TimePicker/Listbox.js.map +1 -1
  78. package/dist/components/TimePicker/Segment.d.ts +6 -0
  79. package/dist/components/TimePicker/Segment.js +6 -0
  80. package/dist/components/TimePicker/Segment.js.map +1 -1
  81. package/dist/components/Truncated/Truncated.d.ts +0 -1
  82. package/dist/components/Truncated/Truncated.js +1 -2
  83. package/dist/components/Truncated/Truncated.js.map +1 -1
  84. package/dist/components/UIProvider/UIProvider.d.ts +0 -1
  85. package/dist/components/UIProvider/UIProvider.js +0 -1
  86. package/dist/components/UIProvider/UIProvider.js.map +1 -1
  87. package/dist/hooks/useLongPress.d.ts +30 -15
  88. package/dist/hooks/useLongPress.js +26 -42
  89. package/dist/hooks/useLongPress.js.map +1 -1
  90. package/dist/styles/base.css +9 -0
  91. package/dist/styles/base.css.js +9 -0
  92. package/package.json +1 -1
  93. package/src/components/BannerAlert/BannerAlert.tsx +5 -5
  94. package/src/components/Breadcrumb/BreadcrumbDropdown.tsx +6 -0
  95. package/src/components/CheckboxGroup/CheckboxGroupExample.tsx +1 -0
  96. package/src/components/Drawer/Drawer.tsx +0 -1
  97. package/src/components/Field/FieldDescription.tsx +7 -5
  98. package/src/components/Field/FieldError.tsx +6 -0
  99. package/src/components/Field/FieldLabel.tsx +6 -0
  100. package/src/components/Field/utils.ts +5 -0
  101. package/src/components/InlineAlert/SvgWarningTwoTone.tsx +6 -0
  102. package/src/components/InputNumber/IncrementButton.tsx +21 -11
  103. package/src/components/InputNumber/InputNumber.tsx +33 -31
  104. package/src/components/InputNumber/InputNumberExample.tsx +1 -0
  105. package/src/components/InputNumber/input-number.scss +10 -0
  106. package/src/components/Link/Link.tsx +1 -1
  107. package/src/components/OTPInput/OTPInput.tsx +5 -1
  108. package/src/components/Pagination/PageList.tsx +6 -0
  109. package/src/components/Scrim/Scrim.tsx +0 -1
  110. package/src/components/Select/Select.tsx +11 -11
  111. package/src/components/Skeleton/Circular.tsx +6 -0
  112. package/src/components/Skeleton/Photo.tsx +6 -0
  113. package/src/components/Skeleton/Profile.tsx +6 -0
  114. package/src/components/Skeleton/Rectangular.tsx +6 -0
  115. package/src/components/Skeleton/Thumbnail.tsx +6 -0
  116. package/src/components/Slider/SliderIntervalDots.tsx +6 -0
  117. package/src/components/Snackbar/Manager.tsx +0 -1
  118. package/src/components/Snackbar/Snackbar.tsx +0 -1
  119. package/src/components/TabList/TabList.tsx +1 -2
  120. package/src/components/Table/Footer.tsx +6 -0
  121. package/src/components/TimePicker/Listbox.tsx +6 -0
  122. package/src/components/TimePicker/Segment.tsx +6 -0
  123. package/src/components/Truncated/Truncated.tsx +1 -2
  124. package/src/components/UIProvider/UIProvider.tsx +0 -1
  125. package/src/hooks/useLongPress.ts +58 -48
  126. package/src/styles/base.scss +9 -0
  127. package/dist/components/Truncated/truncated.css +0 -8
  128. package/dist/components/Truncated/truncated.css.js +0 -13
  129. package/src/components/Truncated/truncated.scss +0 -8
@@ -1,50 +1,34 @@
1
- import { useRef, useState } from 'react';
1
+ import { useRef } from 'react';
2
2
  import { useTimeout } from './useTimeout';
3
- export const MIN_INTERVAL = 250; // Minimum interval in milliseconds
4
- export const INTERVAL_DECREASE_FACTOR = 0.75; // Percent by which the interval decreases each time
5
- export const INITIAL_INTERVAL = 1000; // Initial interval in milliseconds
6
- const isTriggerElementDisabled = (element) => !element ||
7
- element.disabled ||
8
- element.getAttribute('disabled') === 'true' ||
9
- element.getAttribute('aria-disabled') === 'true' ||
10
- element.getAttribute('data-disabled') === 'true' ||
11
- !element.isConnected ||
12
- !element.offsetParent;
13
- export function useLongPress(callback, disabled) {
3
+ /**
4
+ * A hook that provides long press functionality. The provided callback will be invoked once immediately on press, and
5
+ * then repeatedly after a delay, with the delay decreasing by a specified amount after each repeat.
6
+ */
7
+ export function useLongPress({ callback, delay: initialDelay = 750, delayDecrement = 15, delayMin = 100, }) {
14
8
  const timeout = useTimeout();
15
- const intervalRef = useRef(INITIAL_INTERVAL);
16
- const [triggerElement, setTriggerElement] = useState(null);
17
- if (disabled)
18
- return {
19
- onMouseDown: () => { },
20
- onMouseUp: () => { },
21
- setTriggerElement: () => { },
22
- };
23
- const run = () => {
24
- // If the element is not connected or disabled, clear the timeout, and prevent the callback
25
- if (isTriggerElementDisabled(triggerElement))
9
+ const isPressing = useRef(false);
10
+ const delay = useRef(initialDelay);
11
+ const setPressing = (pressing) => {
12
+ isPressing.current = pressing;
13
+ if (pressing) {
14
+ if (!callback())
15
+ return setPressing(false);
16
+ timeout.set(() => {
17
+ if (!isPressing.current)
18
+ return setPressing(false);
19
+ const decrementMs = (delay.current * delayDecrement) / 100;
20
+ delay.current = delay.current <= delayMin ? delayMin : delay.current - decrementMs;
21
+ setPressing(true);
22
+ }, delay.current);
26
23
  return;
27
- callback();
28
- // Decrease the interval for the next call, but not below MIN_INTERVAL
29
- if (intervalRef.current > MIN_INTERVAL)
30
- intervalRef.current = intervalRef.current * INTERVAL_DECREASE_FACTOR;
31
- timeout.set(run, intervalRef.current);
24
+ }
25
+ delay.current = initialDelay;
26
+ timeout.clear();
32
27
  };
33
28
  return {
34
- onMouseDown: (event) => {
35
- event.preventDefault();
36
- intervalRef.current = INITIAL_INTERVAL;
37
- callback();
38
- timeout.set(run, intervalRef.current);
39
- },
40
- onMouseUp: () => {
41
- timeout.clear();
42
- },
43
- onMouseLeave: () => {
44
- timeout.clear();
45
- },
46
- setTriggerElement,
29
+ onPointerDown: () => setPressing(true),
30
+ onPointerLeave: () => setPressing(false),
31
+ onPointerUp: () => setPressing(false),
47
32
  };
48
33
  }
49
- /** Copyright 2025 Anywhere Real Estate - CC BY 4.0 */
50
34
  //# sourceMappingURL=useLongPress.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useLongPress.js","sourceRoot":"","sources":["../../src/hooks/useLongPress.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAc,MAAM,OAAO,CAAC;AAErD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,CAAC,MAAM,YAAY,GAAG,GAAG,CAAC,CAAC,mCAAmC;AACpE,MAAM,CAAC,MAAM,wBAAwB,GAAG,IAAI,CAAC,CAAC,oDAAoD;AAClG,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,CAAC,CAAC,mCAAmC;AAEzE,MAAM,wBAAwB,GAAG,CAAC,OAA2B,EAAE,EAAE,CAC7D,CAAC,OAAO;IACP,OAA6B,CAAC,QAAQ;IACvC,OAAO,CAAC,YAAY,CAAC,UAAU,CAAC,KAAK,MAAM;IAC3C,OAAO,CAAC,YAAY,CAAC,eAAe,CAAC,KAAK,MAAM;IAChD,OAAO,CAAC,YAAY,CAAC,eAAe,CAAC,KAAK,MAAM;IAChD,CAAC,OAAO,CAAC,WAAW;IACpB,CAAC,OAAO,CAAC,YAAY,CAAC;AAE1B,MAAM,UAAU,YAAY,CAAC,QAAoB,EAAE,QAAiB;IAChE,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,MAAM,WAAW,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC;IAE7C,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,QAAQ,CAA2B,IAAI,CAAC,CAAC;IAErF,IAAI,QAAQ;QACR,OAAO;YACH,WAAW,EAAE,GAAG,EAAE,GAAE,CAAC;YACrB,SAAS,EAAE,GAAG,EAAE,GAAE,CAAC;YACnB,iBAAiB,EAAE,GAAG,EAAE,GAAE,CAAC;SAC9B,CAAC;IAEN,MAAM,GAAG,GAAG,GAAG,EAAE;QACb,2FAA2F;QAC3F,IAAI,wBAAwB,CAAC,cAAc,CAAC;YAAE,OAAO;QACrD,QAAQ,EAAE,CAAC;QACX,sEAAsE;QACtE,IAAI,WAAW,CAAC,OAAO,GAAG,YAAY;YAAE,WAAW,CAAC,OAAO,GAAG,WAAW,CAAC,OAAO,GAAG,wBAAwB,CAAC;QAC7G,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAC1C,CAAC,CAAC;IAEF,OAAO;QACH,WAAW,EAAE,CAAC,KAAiB,EAAE,EAAE;YAC/B,KAAK,CAAC,cAAc,EAAE,CAAC;YACvB,WAAW,CAAC,OAAO,GAAG,gBAAgB,CAAC;YACvC,QAAQ,EAAE,CAAC;YACX,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;QAC1C,CAAC;QACD,SAAS,EAAE,GAAG,EAAE;YACZ,OAAO,CAAC,KAAK,EAAE,CAAC;QACpB,CAAC;QACD,YAAY,EAAE,GAAG,EAAE;YACf,OAAO,CAAC,KAAK,EAAE,CAAC;QACpB,CAAC;QACD,iBAAiB;KACpB,CAAC;AACN,CAAC;AAED,sDAAsD"}
1
+ {"version":3,"file":"useLongPress.js","sourceRoot":"","sources":["../../src/hooks/useLongPress.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAyB1C;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,EACzB,QAAQ,EACR,KAAK,EAAE,YAAY,GAAG,GAAG,EACzB,cAAc,GAAG,EAAE,EACnB,QAAQ,GAAG,GAAG,GACD;IACb,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IACjC,MAAM,KAAK,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;IAEnC,MAAM,WAAW,GAAG,CAAC,QAAiB,EAAE,EAAE;QACtC,UAAU,CAAC,OAAO,GAAG,QAAQ,CAAC;QAE9B,IAAI,QAAQ,EAAE,CAAC;YACX,IAAI,CAAC,QAAQ,EAAE;gBAAE,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC;YAE3C,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE;gBACb,IAAI,CAAC,UAAU,CAAC,OAAO;oBAAE,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC;gBAEnD,MAAM,WAAW,GAAG,CAAC,KAAK,CAAC,OAAO,GAAG,cAAc,CAAC,GAAG,GAAG,CAAC;gBAC3D,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,IAAI,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,GAAG,WAAW,CAAC;gBAEnF,WAAW,CAAC,IAAI,CAAC,CAAC;YACtB,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;YAClB,OAAO;QACX,CAAC;QAED,KAAK,CAAC,OAAO,GAAG,YAAY,CAAC;QAC7B,OAAO,CAAC,KAAK,EAAE,CAAC;IACpB,CAAC,CAAC;IAEF,OAAO;QACH,aAAa,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC;QACtC,cAAc,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC;QACxC,WAAW,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC;KACxC,CAAC;AACN,CAAC"}
@@ -241,6 +241,15 @@ body[data-bspk] [data-bspk=link][data-subtle-inverse][disabled] {
241
241
  left: auto;
242
242
  }
243
243
 
244
+ [data-truncated] {
245
+ max-width: 100%;
246
+ display: inline-block;
247
+ overflow: hidden;
248
+ text-overflow: ellipsis;
249
+ white-space: nowrap;
250
+ background-color: transparent;
251
+ }
252
+
244
253
  [data-sr-only] {
245
254
  height: 1px;
246
255
  overflow: hidden;
@@ -244,6 +244,15 @@ body[data-bspk] [data-bspk=link][data-subtle-inverse][disabled] {
244
244
  left: auto;
245
245
  }
246
246
 
247
+ [data-truncated] {
248
+ max-width: 100%;
249
+ display: inline-block;
250
+ overflow: hidden;
251
+ text-overflow: ellipsis;
252
+ white-space: nowrap;
253
+ background-color: transparent;
254
+ }
255
+
247
256
  [data-sr-only] {
248
257
  height: 1px;
249
258
  overflow: hidden;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bspk/ui",
3
- "version": "1.3.9",
3
+ "version": "1.3.10",
4
4
  "license": "CC-BY-4.0",
5
5
  "type": "module",
6
6
  "files": [
@@ -56,13 +56,13 @@ export type BannerAlertProps = {
56
56
  *
57
57
  * <BannerAlert
58
58
  * elevated={true}
59
- * variant="error"
60
- * header="Error"
61
- * body="There was an error processing your request."
59
+ * variant="success"
60
+ * header="Success"
61
+ * body="Your request was processed successfully."
62
62
  * onClose={() => sendSnackbar('Alert closed')}
63
63
  * callToAction={{
64
- * label = 'Click me',
65
- * onClick = () => action('Call to action clicked!'),
64
+ * label: 'Click me',
65
+ * onClick: () => action('Call to action clicked!'),
66
66
  * }}
67
67
  * />;
68
68
  *
@@ -37,6 +37,12 @@ export type BreadcrumbDropdownProps = ScrollListItemsStyleProps & {
37
37
  id: string;
38
38
  };
39
39
 
40
+ /**
41
+ * The BreadcrumbDropdown component is used to display a dropdown menu within a breadcrumb navigation.
42
+ *
43
+ * @name BreadcrumbDropdown
44
+ * @parent Breadcrumb
45
+ */
40
46
  export function BreadcrumbDropdown({ items: itemsProp, id, scrollLimit }: BreadcrumbDropdownProps) {
41
47
  const menuId = `${id}-menu`;
42
48
 
@@ -58,6 +58,7 @@ export const presets: Preset<CheckboxGroupProps>[] = [
58
58
  export const CheckboxGroupExample: ComponentExample<CheckboxGroupProps> = {
59
59
  presets,
60
60
  defaultState: {
61
+ selectAll: true,
61
62
  options: [
62
63
  { label: 'Option 1', value: 'option1', description: 'Description for option 1' },
63
64
  {
@@ -76,7 +76,6 @@ export type DrawerProps = Pick<DialogProps, 'container' | 'disableFocusTrap' | '
76
76
  * @name Drawer
77
77
  * @phase UXReview
78
78
  */
79
-
80
79
  export function Drawer({
81
80
  header,
82
81
  children,
@@ -1,6 +1,12 @@
1
1
  import { useFieldContext, describedById } from './utils';
2
2
 
3
- function FieldDescription({ children }: { children?: string }) {
3
+ /**
4
+ * FieldDescription component displays a description associated with a form field.
5
+ *
6
+ * @name FieldDescription
7
+ * @parent Field
8
+ */
9
+ export function FieldDescription({ children }: { children?: string }) {
4
10
  const { id } = useFieldContext();
5
11
 
6
12
  return children ? (
@@ -9,7 +15,3 @@ function FieldDescription({ children }: { children?: string }) {
9
15
  </p>
10
16
  ) : null;
11
17
  }
12
-
13
- FieldDescription.displayName = 'FieldDescription';
14
-
15
- export { FieldDescription };
@@ -6,6 +6,12 @@ export type FieldErrorProps = {
6
6
  children?: string;
7
7
  };
8
8
 
9
+ /**
10
+ * FieldError component displays an error message associated with a form field.
11
+ *
12
+ * @name FieldError
13
+ * @parent Field
14
+ */
9
15
  export function FieldError({ children }: FieldErrorProps) {
10
16
  const { id } = useFieldContext();
11
17
 
@@ -14,6 +14,12 @@ export type FieldLabelProps<As extends ElementType = ElementType> = Pick<FieldCo
14
14
  as?: As;
15
15
  };
16
16
 
17
+ /**
18
+ * FieldLabel component displays a label associated with a form field.
19
+ *
20
+ * @name FieldLabel
21
+ * @parent Field
22
+ */
17
23
  export function FieldLabel<As extends ElementType = ElementType>({
18
24
  children,
19
25
  labelTrailing,
@@ -28,6 +28,11 @@ export type FieldContext = FieldContextProps & {
28
28
 
29
29
  export const fieldContext = createContext<FieldContext | null>(null);
30
30
 
31
+ /**
32
+ * Retrieves the current Field context.
33
+ *
34
+ * Will return a default context if used outside of a Field component.
35
+ */
31
36
  export function useFieldContext(): FieldContext {
32
37
  return (
33
38
  useContext(fieldContext) || {
@@ -1,3 +1,9 @@
1
+ /**
2
+ * SvgWarningTwoTone component renders a two-tone warning SVG icon.
3
+ *
4
+ * @name SvgWarningTwoTone
5
+ * @parent InlineAlert
6
+ */
1
7
  export function SvgWarningTwoTone() {
2
8
  return (
3
9
  <svg fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
@@ -3,29 +3,39 @@ import { SvgRemove } from '@bspk/icons/Remove';
3
3
  import { useLongPress } from '-/hooks/useLongPress';
4
4
 
5
5
  export type IncrementButtonProps = {
6
+ /** Whether the button is disabled. */
6
7
  disabled: boolean;
7
- increment: -1 | 1;
8
- onIncrement: (increment: -1 | 1) => void;
8
+ /** The kind of increment button, either 'add' or 'remove'. */
9
+ kind: 'add' | 'remove';
10
+ /** The ID of the associated input element. */
9
11
  inputId: string;
12
+ /** Function to trigger the increment action. */
13
+ triggerIncrement: (kind: 'add' | 'remove') => boolean;
10
14
  };
11
15
 
12
- export function IncrementButton({ increment, disabled, onIncrement, inputId }: IncrementButtonProps) {
13
- const add = increment === 1;
14
-
15
- const { setTriggerElement, ...handlers } = useLongPress(() => onIncrement(increment), disabled);
16
+ /**
17
+ * A button component for incrementing or decrementing the InputNumber.
18
+ *
19
+ * @name IncrementButton
20
+ * @parent InputNumber
21
+ */
22
+ export function IncrementButton({ inputId, kind, disabled, triggerIncrement }: IncrementButtonProps) {
23
+ const { ...pressHandlers } = useLongPress({
24
+ callback: () => triggerIncrement(kind),
25
+ });
16
26
 
17
27
  return (
18
28
  <button
19
- {...handlers}
29
+ {...pressHandlers}
20
30
  aria-controls={inputId}
21
- aria-hidden="true"
22
- data-increment={increment}
31
+ aria-label={kind === 'add' ? 'Increase value' : 'Decrease value'}
32
+ data-bspk="input-number--increment-button"
33
+ data-kind={kind}
23
34
  disabled={disabled}
24
- ref={setTriggerElement}
25
35
  tabIndex={-1}
26
36
  type="button"
27
37
  >
28
- {add ? <SvgAdd /> : <SvgRemove />}
38
+ {kind === 'add' ? <SvgAdd aria-hidden /> : <SvgRemove aria-hidden />}
29
39
  </button>
30
40
  );
31
41
  }
@@ -1,14 +1,16 @@
1
1
  import './input-number.scss';
2
- import { useMemo } from 'react';
2
+ import { useEffect, useRef } from 'react';
3
3
  import { IncrementButton } from './IncrementButton';
4
4
  import { useFieldInit } from '-/components/Field';
5
5
  import { useId } from '-/hooks/useId';
6
6
  import { CommonProps, FieldControlProps } from '-/types/common';
7
7
 
8
- function isNumber(value: unknown, fallbackValue: number | undefined = undefined): number | undefined {
8
+ function isNumber(value: unknown): number | undefined;
9
+ function isNumber(value: unknown, fallbackValue: number): number;
10
+ function isNumber(value: unknown, fallbackValue?: number): number | undefined {
9
11
  if (typeof value === 'number') return value;
10
12
  if (typeof value !== 'string') return fallbackValue;
11
- const num = Number(value);
13
+ const num = parseFloat(value);
12
14
  return isNaN(num) ? fallbackValue : num;
13
15
  }
14
16
 
@@ -108,14 +110,25 @@ export function InputNumber({
108
110
  readOnly,
109
111
  invalidProp,
110
112
  });
111
-
112
113
  const max = typeof maxProp === 'number' && maxProp >= min ? maxProp : Number.MAX_SAFE_INTEGER;
113
114
  const centered = align !== 'left';
114
115
  const inputId = useId(id);
115
- const value = useMemo(() => isNumber(valueProp) || 0, [valueProp]);
116
+ const value = isNumber(valueProp, min);
117
+ const removeDisabled = disabled || value + step * -1 < min;
118
+ const addDisabled = disabled || value + step > max;
119
+
120
+ const valueRef = useRef(value);
116
121
 
117
- const handleIncrement = (increment: -1 | 1) => {
118
- onChange(value + increment * step);
122
+ useEffect(() => {
123
+ valueRef.current = value;
124
+ }, [value]);
125
+
126
+ const incrementHandler = (kind: 'add' | 'remove') => {
127
+ const increment = kind === 'add' ? step : step * -1;
128
+ const next = valueRef.current + increment;
129
+ if (next < min || next > max) return false;
130
+ onChange(next);
131
+ return true;
119
132
  };
120
133
 
121
134
  return (
@@ -128,14 +141,6 @@ export function InputNumber({
128
141
  data-size={size}
129
142
  data-stepper-input
130
143
  >
131
- {!!centered && (
132
- <IncrementButton
133
- disabled={disabled ? true : value + -1 < min}
134
- increment={-1}
135
- inputId={inputId}
136
- onIncrement={handleIncrement}
137
- />
138
- )}
139
144
  <input
140
145
  {...inputElementProps}
141
146
  aria-describedby={ariaDescribedBy || undefined}
@@ -151,32 +156,29 @@ export function InputNumber({
151
156
  max={max}
152
157
  min={min}
153
158
  name={name}
159
+ onBlur={(e) => {
160
+ const next = isNumber(e.target.value, min);
161
+ e.target.value = next?.toString() || '';
162
+ onChange(next);
163
+ }}
154
164
  onChange={(e) => {
155
- onChange(isNumber(e.target.value));
165
+ const next = isNumber(e.target.value, min);
166
+ onChange(next);
156
167
  }}
157
168
  readOnly={readOnly}
158
169
  required={required}
159
170
  step={step}
160
171
  type="number"
161
- value={value}
172
+ value={value !== undefined ? value : ''}
162
173
  />
163
- {!centered && (
164
- <>
165
- <div aria-hidden data-divider />
166
- <IncrementButton
167
- disabled={!!disabled || value + -1 < min}
168
- increment={-1}
169
- inputId={inputId}
170
- onIncrement={handleIncrement}
171
- />
172
- </>
173
- )}
174
+ <div aria-hidden data-divider />
174
175
  <IncrementButton
175
- disabled={!!disabled || value + 1 > max}
176
- increment={1}
176
+ disabled={removeDisabled}
177
177
  inputId={inputId}
178
- onIncrement={handleIncrement}
178
+ kind="remove"
179
+ triggerIncrement={incrementHandler}
179
180
  />
181
+ <IncrementButton disabled={addDisabled} inputId={inputId} kind="add" triggerIncrement={incrementHandler} />
180
182
  </div>
181
183
  );
182
184
  }
@@ -6,4 +6,5 @@ export const InputNumberExample: ComponentExample<InputNumberProps> = {
6
6
  'aria-label': 'input number aria-label',
7
7
  },
8
8
  render: ({ props, Component }) => <Component {...props} />,
9
+ variants: false,
9
10
  };
@@ -129,6 +129,16 @@
129
129
  --height: var(--spacing-sizing-12);
130
130
  --svg-width: var(--spacing-sizing-06);
131
131
  }
132
+
133
+ &[data-centered] {
134
+ button:first-of-type {
135
+ order: -1;
136
+ }
137
+
138
+ [data-divider] {
139
+ display: none;
140
+ }
141
+ }
132
142
  }
133
143
 
134
144
  /** Copyright 2025 Anywhere Real Estate - CC BY 4.0 */
@@ -46,7 +46,7 @@ export type LinkProps = Pick<CommonPropsLibrary, 'disabled'> & {
46
46
  * @example
47
47
  * import { Link } from '@bspk/ui/Link';
48
48
  *
49
- * <Link href="https://bspk.dev" label="Example label" trailingIcon="external" />;
49
+ * <Link href="https://anywhere.re" label="Example label" trailingIcon="external" />;
50
50
  *
51
51
  * @name Link
52
52
  * @phase UXReview
@@ -34,7 +34,11 @@ export type OTPInputProps = CommonProps<'id' | 'invalid' | 'name' | 'size'> & {
34
34
  * @example
35
35
  * import { OTPInput } from '@bspk/ui/OTPInput';
36
36
  *
37
- * <OTPInput name="2-auth-otp" length={4} value={otpValue} onChange={setOtpValue} />;
37
+ * () => {
38
+ * const [otpValue, setOtpValue] = useState('');
39
+ *
40
+ * <OTPInput name="2-auth" length={4} value={otpValue} onChange={setOtpValue} />;
41
+ * };
38
42
  *
39
43
  * @name OTPInput
40
44
  * @phase UXReview
@@ -3,6 +3,12 @@ import { Button } from '-/components/Button';
3
3
 
4
4
  export type PageListProps = Pick<PaginationProps, 'numPages' | 'onChange' | 'value'>;
5
5
 
6
+ /**
7
+ * PageList component displays a list of page buttons for pagination.
8
+ *
9
+ * @name PageList
10
+ * @parent Pagination
11
+ */
6
12
  export function PageList({ numPages, onChange, value }: PageListProps) {
7
13
  return Array.from({ length: numPages }, (_, index) => {
8
14
  const page = index + 1;
@@ -23,7 +23,6 @@ export type ScrimProps = CommonProps<'owner'> & {
23
23
  * attention to a modal or sheet.
24
24
  *
25
25
  * @name Scrim
26
- *
27
26
  * @phase Utility
28
27
  */
29
28
  export function Scrim({ visible = true, owner, ...props }: ScrimProps) {
@@ -68,16 +68,16 @@ export type SelectProps = CommonProps<'size'> &
68
68
  * @example
69
69
  * import { Select } from '@bspk/ui/Select';
70
70
  *
71
- * const OPTIONS = [
72
- * { id: '1', label: 'Option 1' },
73
- * { id: '2', label: 'Option 2' },
74
- * { id: '3', label: 'Option 3' },
75
- * { id: '4', label: 'Option 4' },
76
- * { id: '5', label: 'Option 5' },
77
- * { id: '6', label: 'Option 6' },
78
- * ];
79
- *
80
71
  * () => {
72
+ * const OPTIONS = [
73
+ * { id: '1', label: 'Option 1' },
74
+ * { id: '2', label: 'Option 2' },
75
+ * { id: '3', label: 'Option 3' },
76
+ * { id: '4', label: 'Option 4' },
77
+ * { id: '5', label: 'Option 5' },
78
+ * { id: '6', label: 'Option 6' },
79
+ * ];
80
+ *
81
81
  * const [selected, setSelected] = useState<string[]>([]);
82
82
  *
83
83
  * return (
@@ -85,7 +85,7 @@ export type SelectProps = CommonProps<'size'> &
85
85
  * // standalone select example
86
86
  * <Select
87
87
  * aria-label="Select an option"
88
- * itemCount={5}
88
+ * scrollLimit={5}
89
89
  * name="example-select"
90
90
  * onChange={setSelected}
91
91
  * options={OPTIONS}
@@ -98,7 +98,7 @@ export type SelectProps = CommonProps<'size'> &
98
98
  * <Field>
99
99
  * <FieldLabel>Select an option</FieldLabel>
100
100
  * <Select
101
- * itemCount={5}
101
+ * scrollLimit={5}
102
102
  * name="example-select"
103
103
  * onChange={setSelected}
104
104
  * options={OPTIONS}
@@ -1,5 +1,11 @@
1
1
  import { Skeleton, SkeletonProps } from './Skeleton';
2
2
 
3
+ /**
4
+ * SkeletonCircular component displays a circular skeleton loader.
5
+ *
6
+ * @name SkeletonCircular
7
+ * @parent Skeleton
8
+ */
3
9
  export function SkeletonCircular(props: Pick<SkeletonProps, 'height' | 'width'>) {
4
10
  return <Skeleton {...props} variant="circular" />;
5
11
  }
@@ -1,5 +1,11 @@
1
1
  import { Skeleton, SkeletonProps } from './Skeleton';
2
2
 
3
+ /**
4
+ * SkeletonPhoto component displays a photo skeleton loader.
5
+ *
6
+ * @name SkeletonPhoto
7
+ * @parent Skeleton
8
+ */
3
9
  export function SkeletonPhoto(props: Pick<SkeletonProps, 'height' | 'width'>) {
4
10
  return <Skeleton {...props} variant="photo" />;
5
11
  }
@@ -1,5 +1,11 @@
1
1
  import { Skeleton, SkeletonProps } from './Skeleton';
2
2
 
3
+ /**
4
+ * SkeletonProfile component displays a profile skeleton loader.
5
+ *
6
+ * @name SkeletonProfile
7
+ * @parent Skeleton
8
+ */
3
9
  export function SkeletonProfile(props: Pick<SkeletonProps, 'height' | 'width'>) {
4
10
  return <Skeleton {...props} variant="profile" />;
5
11
  }
@@ -1,5 +1,11 @@
1
1
  import { Skeleton, SkeletonProps } from './Skeleton';
2
2
 
3
+ /**
4
+ * SkeletonRectangular component displays a rectangular skeleton loader.
5
+ *
6
+ * @name SkeletonRectangular
7
+ * @parent Skeleton
8
+ */
3
9
  export function SkeletonRectangular(props: Pick<SkeletonProps, 'height' | 'width'>) {
4
10
  return <Skeleton {...props} variant="rectangular" />;
5
11
  }
@@ -1,5 +1,11 @@
1
1
  import { Skeleton, SkeletonProps } from './Skeleton';
2
2
 
3
+ /**
4
+ * SkeletonThumbnail component displays a thumbnail skeleton loader.
5
+ *
6
+ * @name SkeletonThumbnail
7
+ * @parent Skeleton
8
+ */
3
9
  export function SkeletonThumbnail(props: Pick<SkeletonProps, 'height' | 'width'>) {
4
10
  return <Skeleton {...props} variant="thumbnail" />;
5
11
  }
@@ -4,6 +4,12 @@ export type IntervalDotProps = Pick<SliderProps<SliderValue>, 'max' | 'min' | 'v
4
4
  step: number;
5
5
  };
6
6
 
7
+ /**
8
+ * SliderIntervalDots component displays interval dots along a slider track.
9
+ *
10
+ * @name SliderIntervalDots
11
+ * @parent Slider
12
+ */
7
13
  export function SliderIntervalDots({ step, max, min, value }: IntervalDotProps) {
8
14
  if (step <= 0) return null;
9
15
 
@@ -33,7 +33,6 @@ const SnackbarEvent = createCustomEvent<SendSnackbarProps | string | typeof CLEA
33
33
  * context. :)
34
34
  *
35
35
  * @name SnackbarManager
36
- *
37
36
  * @phase UXReview
38
37
  */
39
38
  export function SnackbarManager({ defaultTimeout = 5000 }: SnackbarManagerProps) {
@@ -104,7 +104,6 @@ export type SnackbarProps = CommonProps<'id'> & {
104
104
  * };
105
105
  *
106
106
  * @name Snackbar
107
- *
108
107
  * @phase UXReview
109
108
  */
110
109
  export function Snackbar({