@react-md/core 6.3.3 → 6.3.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.
@@ -153,6 +153,11 @@ $_breakpoints: (
153
153
  ),
154
154
  );
155
155
 
156
+ /// @type Boolean
157
+ /// @access private
158
+ $_disable-media-queries: $disable-phone-columns and $disable-tablet-columns and
159
+ $disable-desktop-columns and $disable-large-desktop-columns;
160
+
156
161
  /// The available configurable css variables and mostly used internally for the
157
162
  /// `get-var`, `set-var`, and `use-var` utils.
158
163
  /// @type List
@@ -168,6 +173,7 @@ $variables: (
168
173
  columns,
169
174
  row-max-height,
170
175
  auto-rows-height,
176
+ fallback-media-columns,
171
177
  phone-columns,
172
178
  phone-item-min-size,
173
179
  phone-item-min-height,
@@ -404,6 +410,10 @@ $variables: (
404
410
 
405
411
  @if not $disable-grid {
406
412
  &--grid {
413
+ @if not $_disable-media-queries {
414
+ @include set-var(fallback-media-columns, auto-fit);
415
+ }
416
+
407
417
  display: grid;
408
418
  grid-template-columns: repeat(
409
419
  get-var(columns),
@@ -412,6 +422,9 @@ $variables: (
412
422
  }
413
423
 
414
424
  &--grid-fill {
425
+ @if not $_disable-media-queries {
426
+ @include set-var(fallback-media-columns, auto-fill);
427
+ }
415
428
  @include set-var(columns, auto-fill);
416
429
  }
417
430
 
@@ -427,7 +440,13 @@ $variables: (
427
440
  $disable-size: map.get($feature-flags, size);
428
441
  @if not $disable-columns {
429
442
  &--grid-#{$media} {
430
- @include set-var(columns, get-var($media + "-columns"));
443
+ @include set-var(
444
+ columns,
445
+ get-var(
446
+ $media + "-columns",
447
+ get-var(fallback-media-columns)
448
+ )
449
+ );
431
450
  }
432
451
  }
433
452
 
@@ -217,6 +217,20 @@ export interface BoxOptions {
217
217
  reversed?: boolean;
218
218
  }
219
219
  /**
220
+ * Applies the `className` from the `Box` component to any element.
221
+ *
222
+ * @example Simple Example
223
+ * ```tsx
224
+ * return (
225
+ * <form className={box({ stacked: true})}>
226
+ * {children}
227
+ * </form>
228
+ * );
229
+ * ```
230
+ *
231
+ * If custom media query breakpoints are required, use the {@link boxStyles}
232
+ * function instead which will also set the CSS variables.
233
+ *
220
234
  * @see {@link boxStyles}
221
235
  * @since 6.0.0
222
236
  */
@@ -235,6 +249,31 @@ export interface BoxStylesOptions extends BoxOptions {
235
249
  style?: CSSProperties;
236
250
  }
237
251
  /**
252
+ * Used to apply the styles from the `Box` component to any element by
253
+ * providing a `style` object with CSS variables and a `className`.
254
+ *
255
+ * If you do not need to use
256
+ *
257
+ * @example Simple Example
258
+ * ```tsx
259
+ * return (
260
+ * <form
261
+ * {...boxStyles({
262
+ * grid: true,
263
+ * gridColumns: {
264
+ * phone: 1,
265
+ * desktop: 3,
266
+ * },
267
+ * gridItemSize: {
268
+ * tablet: "12rem",
269
+ * },
270
+ * })}
271
+ * >
272
+ * {children}
273
+ * </form>
274
+ * );
275
+ * ```
276
+ *
238
277
  * @see {@link box}
239
278
  * @since 6.0.0
240
279
  */
@@ -2,6 +2,20 @@ import { cnb } from "cnbuilder";
2
2
  import { bem } from "../utils/bem.js";
3
3
  const styles = bem("rmd-box");
4
4
  /**
5
+ * Applies the `className` from the `Box` component to any element.
6
+ *
7
+ * @example Simple Example
8
+ * ```tsx
9
+ * return (
10
+ * <form className={box({ stacked: true})}>
11
+ * {children}
12
+ * </form>
13
+ * );
14
+ * ```
15
+ *
16
+ * If custom media query breakpoints are required, use the {@link boxStyles}
17
+ * function instead which will also set the CSS variables.
18
+ *
5
19
  * @see {@link boxStyles}
6
20
  * @since 6.0.0
7
21
  */ export function box(options = {}) {
@@ -112,6 +126,31 @@ const styles = bem("rmd-box");
112
126
  return style;
113
127
  }
114
128
  /**
129
+ * Used to apply the styles from the `Box` component to any element by
130
+ * providing a `style` object with CSS variables and a `className`.
131
+ *
132
+ * If you do not need to use
133
+ *
134
+ * @example Simple Example
135
+ * ```tsx
136
+ * return (
137
+ * <form
138
+ * {...boxStyles({
139
+ * grid: true,
140
+ * gridColumns: {
141
+ * phone: 1,
142
+ * desktop: 3,
143
+ * },
144
+ * gridItemSize: {
145
+ * tablet: "12rem",
146
+ * },
147
+ * })}
148
+ * >
149
+ * {children}
150
+ * </form>
151
+ * );
152
+ * ```
153
+ *
115
154
  * @see {@link box}
116
155
  * @since 6.0.0
117
156
  */ export function boxStyles(options) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/box/styles.ts"],"sourcesContent":["import { cnb } from \"cnbuilder\";\nimport { type CSSProperties } from \"react\";\n\nimport { type DefinedCSSVariableName } from \"../theme/types.js\";\nimport { type IsEmptyObject, type OverridableStringUnion } from \"../types.js\";\nimport { bem } from \"../utils/bem.js\";\n\nconst styles = bem(\"rmd-box\");\n\ndeclare module \"react\" {\n interface CSSProperties {\n \"--rmd-box-gap\"?: string | number;\n \"--rmd-box-padding\"?: string | number;\n \"--rmd-box-padding-h\"?: string | number;\n \"--rmd-box-padding-v\"?: string | number;\n \"--rmd-box-item-min-size\"?: string | number;\n \"--rmd-box-item-min-height\"?: string | number;\n \"--rmd-box-columns\"?: string | number;\n \"--rmd-box-row-max-height\"?: string;\n \"--rmd-box-auto-rows-height\"?: string;\n \"--rmd-box-phone-columns\"?: number | string;\n \"--rmd-box-phone-item-min-height\"?: number | string;\n \"--rmd-box-phone-item-min-size\"?: number | string;\n \"--rmd-box-tablet-columns\"?: number | string;\n \"--rmd-box-tablet-item-min-size\"?: number | string;\n \"--rmd-box-tablet-item-min-height\"?: number | string;\n \"--rmd-box-desktop-columns\"?: number | string;\n \"--rmd-box-desktop-item-min-size\"?: number | string;\n \"--rmd-box-desktop-item-min-height\"?: number | string;\n \"--rmd-box-large-desktop-columns\"?: number | string;\n \"--rmd-box-large-desktop-item-min-size\"?: number | string;\n \"--rmd-box-large-desktop-item-min-height\"?: number | string;\n }\n}\n\n/** @since 6.2.0 */\nexport interface BoxAlignItemsOverrides {}\n/** @since 6.2.0 */\nexport interface BoxJustifyContentOverrides {}\n/** @since 6.2.0 */\nexport interface BoxGridNameOverrides {}\n\n/**\n * @since 6.0.0\n */\nexport type BoxAlignItems = OverridableStringUnion<\n \"start\" | \"flex-start\" | \"center\" | \"end\" | \"flex-end\" | \"stretch\",\n BoxAlignItemsOverrides\n>;\n\n/**\n * @since 6.0.0\n */\nexport type BoxJustifyContent = OverridableStringUnion<\n BoxAlignItems | \"space-around\" | \"space-between\" | \"space-evenly\",\n BoxJustifyContentOverrides\n>;\n\n/**\n * @since 6.0.0\n */\nexport type BoxFlexDirection = \"row\" | \"column\";\n\n/**\n * @since 6.0.0\n */\nexport type BoxGridColumns = \"fit\" | \"fill\" | number;\n\n/**\n * @since 6.2.0\n */\nexport type BoxGridName =\n IsEmptyObject<BoxGridNameOverrides> extends true\n ? string\n : OverridableStringUnion<never, BoxGridNameOverrides>;\n\n/**\n * @since 6.0.0\n */\nexport type BoxBreakpoints = \"phone\" | \"tablet\" | \"desktop\" | \"largeDesktop\";\n\n/**\n * @since 6.0.0\n */\nexport type BoxGridBreakpointColumns = {\n [key in BoxBreakpoints]?: BoxGridColumns;\n};\n\n/**\n * @since 6.0.0\n */\nexport type BoxGridBreakpointItemSize = {\n [key in BoxBreakpoints]?: string;\n};\n\n/**\n * @since 6.0.0\n */\nexport interface BoxOptions {\n className?: string;\n\n /**\n * Set this to `true` to use `display: grid` instead of `display: flex`.\n *\n * @defaultValue `false`\n */\n grid?: boolean;\n\n /**\n * Set this to `true` to apply `width: 100%`. This can be useful when using\n * nested box layouts.\n *\n * @defaultValue `false`\n */\n fullWidth?: boolean;\n\n /**\n * Set this to `true` to prevent gap between items.\n *\n * @defaultValue `false`\n */\n disableGap?: boolean | \"row\" | \"column\";\n\n /**\n * Set this to `true` to set `flex-wrap: nowrap`.\n *\n * @defaultValue `false`\n */\n disableWrap?: boolean;\n\n /**\n * Set this to `true` to disable the default padding.\n *\n * @defaultValue `false`\n */\n disablePadding?: boolean;\n\n /**\n * This should match one of the names in the `$box-grids` map. So for example:\n *\n * ```scss\n * @use \"react-md\" with (\n * $box-grids: (\n * small: (\n * min: 5rem\n * ),\n * medium: (\n * min: 7rem,\n * gap: 0.5rem,\n * padding: 2rem,\n * ),\n * ),\n * );\n * ```\n *\n * ```ts\n * declare module \"@react-md/core/box/styles\" {\n * interface BoxGridNameOverrides {\n * small: true;\n * medium: true;\n * }\n * }\n * ```\n *\n * The `gridName` should be `\"small\" | \"medium\"`.\n *\n * @defaultValue `\"\"`\n */\n gridName?: BoxGridName;\n\n /**\n * The default behavior for a grid is to automatically determine the number\n * of columns to render by placing as many items as possible with a specific\n * item min-width and the defined gap between items. Once the number of\n * columns has been determined, place the items in the grid and expand to the\n * full column width.\n *\n * This prop is a convenience prop to control how to display items when there\n * are not enough to span all columns without a separate SCSS file.\n *\n * i.e. 3 items were provided but 4 can be rendered.\n *\n * - `\"fit\"` - fill the entire width with columns and stretch columns to fill\n * the remaining space\n * - `\"fill\"` - fill the entire width with columns and add empty columns to\n * fill the remaining space\n * - `number` - ignore the auto layout behavior and specify the number of\n * columns to use instead.\n *\n * If additional responsive behavior is required, an object can be provided\n * to define the column behavior for: phone, tablet, desktop, or\n * largeDesktop.\n *\n * @see {@link gridItemSize} for how the number of columns are determined.\n * @defaultValue `\"fit\"`\n */\n gridColumns?: BoxGridColumns | BoxGridBreakpointColumns;\n\n /**\n * This prop can be used to override the default `--rmd-box-item-min-size`\n * for the grid without a separate SCSS file. Since this is set as a CSS variable,\n * the value must be a number with a unit to work correctly. i.e. `10rem`\n * instead of `160`.\n *\n * If additional responsive behavior is required, an object can be provided\n * to define the column behavior for: phone, tablet, desktop, or\n * largeDesktop.\n *\n * @see {@link https://react-md.dev/sassdoc/box#variables-box-item-min-size}\n */\n gridItemSize?: string | BoxGridBreakpointItemSize;\n\n /**\n * Set this to `true` to enable equal height rows within the grid based\n * on the current `max-height`. This requires the `max-height` to be set\n * on the `Box` either by:\n *\n * - a custom class name that sets `max-height`\n * - `core.box-set-var(auto-rows-height, VALUE)` on the box or a parent element\n *\n * @defaultValue `false`\n */\n gridAutoRows?: boolean;\n\n /**\n * @defaultValue `\"\"`\n */\n align?: BoxAlignItems;\n\n /**\n * The default value is really `center` or whatever the\n * `$box-default-align-items` is set to.\n *\n * @defaultValue `\"\"`\n */\n justify?: BoxJustifyContent;\n\n /**\n * Set this to `true` to set `flex-direction: column` which will stack all\n * items in the box.\n *\n * @defaultValue `false`\n */\n stacked?: boolean;\n\n /**\n * Set this to `true` to reverse the `flex-direction`. i.e.\n * - `flex-direction: row-reverse`\n * - `flex-direction: column-reverse`\n *\n * @defaultValue `false`\n */\n reversed?: boolean;\n}\n\n/**\n * @see {@link boxStyles}\n * @since 6.0.0\n */\nexport function box(options: BoxOptions = {}): string {\n const {\n className,\n align = \"\",\n grid,\n gridName = \"\",\n gridColumns = \"fit\",\n gridItemSize,\n gridAutoRows,\n justify = \"\",\n stacked,\n reversed,\n fullWidth,\n disableGap,\n disableWrap,\n disablePadding,\n } = options;\n let phoneColumns: BoxGridColumns | undefined;\n let phoneItemSize: string | number | undefined;\n let tabletColumns: BoxGridColumns | undefined;\n let tabletItemSize: string | number | undefined;\n let desktopColumns: BoxGridColumns | undefined;\n let desktopItemSize: string | number | undefined;\n let largeDesktopColumns: BoxGridColumns | undefined;\n let largeDesktopItemSize: string | number | undefined;\n if (gridColumns && typeof gridColumns === \"object\") {\n ({\n phone: phoneColumns,\n tablet: tabletColumns,\n desktop: desktopColumns,\n largeDesktop: largeDesktopColumns,\n } = gridColumns);\n }\n if (gridItemSize && typeof gridItemSize === \"object\") {\n ({\n phone: phoneItemSize,\n tablet: tabletItemSize,\n desktop: desktopItemSize,\n largeDesktop: largeDesktopItemSize,\n } = gridItemSize);\n }\n\n const isItemSizeEnabled = (\n value: string | number | undefined\n ): boolean | undefined => grid && (!!value || value === 0);\n const isColumnsEnabled = (\n value: BoxGridColumns | BoxGridBreakpointColumns | undefined\n ): boolean | undefined => grid && typeof value === \"number\";\n\n return cnb(\n styles({\n gap: !disableGap,\n \"gap-h\": disableGap === \"row\",\n \"gap-v\": disableGap === \"column\",\n wrap: !disableWrap,\n padded: !disablePadding,\n column: stacked && !reversed,\n reverse: !stacked && reversed,\n \"column-reverse\": stacked && reversed,\n \"full-width\": fullWidth,\n grid,\n \"grid-fill\": grid && gridColumns === \"fill\",\n \"grid-size\": isColumnsEnabled(gridColumns),\n \"grid-phone\": grid && (phoneColumns || phoneItemSize),\n \"grid-phone-size\":\n isColumnsEnabled(phoneColumns) || isItemSizeEnabled(phoneItemSize),\n \"grid-tablet\": grid && (tabletColumns || tabletItemSize),\n \"grid-tablet-size\":\n isColumnsEnabled(tabletColumns) || isItemSizeEnabled(tabletItemSize),\n \"grid-desktop\": grid && (desktopColumns || desktopItemSize),\n \"grid-desktop-size\":\n isColumnsEnabled(desktopColumns) || isItemSizeEnabled(desktopItemSize),\n \"grid-large-desktop\":\n grid && (largeDesktopColumns || largeDesktopItemSize),\n \"grid-large-desktop-size\":\n isColumnsEnabled(largeDesktopColumns) ||\n isItemSizeEnabled(largeDesktopItemSize),\n \"grid-auto-rows\": grid && gridAutoRows,\n [gridName]: grid && gridName,\n \"align-start\": align === \"start\" || align === \"flex-start\",\n \"align-center\": align === \"center\",\n \"align-end\": align === \"end\" || align === \"flex-end\",\n \"align-stretch\": align === \"stretch\",\n \"justify-center\": justify === \"center\",\n \"justify-start\": justify === \"start\" || justify === \"flex-start\",\n \"justify-end\": justify === \"end\" || justify === \"flex-end\",\n \"justify-stretch\": justify === \"stretch\",\n \"justify-around\": justify === \"space-around\",\n \"justify-between\": justify === \"space-between\",\n \"justify-evenly\": justify === \"space-evenly\",\n }),\n className\n );\n}\n\n/**\n * @since 6.0.0\n * @internal\n */\ninterface ApplyOptions {\n media: keyof BoxGridBreakpointColumns | \"\";\n style: CSSProperties | undefined;\n type: \"columns\" | \"size\";\n value:\n | BoxGridColumns\n | BoxGridBreakpointColumns\n | string\n | BoxGridBreakpointItemSize\n | undefined;\n}\n\n/**\n * @since 6.0.0\n * @internal\n */\nfunction applyBoxVar(options: ApplyOptions): CSSProperties | undefined {\n const { type, media, style, value } = options;\n const expectedType = type === \"columns\" ? \"number\" : \"string\";\n if (typeof value !== expectedType) {\n return style;\n }\n\n const suffix = type === \"columns\" ? type : \"item-min-size\";\n let varName: DefinedCSSVariableName = `--rmd-box-${suffix}`;\n if (media === \"largeDesktop\") {\n varName = `--rmd-box-large-desktop-${suffix}`;\n } else if (media) {\n varName = `--rmd-box-${media}-${suffix}`;\n }\n\n return {\n ...style,\n [varName]: value,\n };\n}\n\n/**\n * @since 6.0.0\n * @internal\n */\nconst BREAKPOINTS = [\"phone\", \"tablet\", \"desktop\", \"largeDesktop\"] as const;\n\n/**\n * @since 6.0.0\n * @internal\n */\nfunction applyBoxVarGroup(\n options: Pick<ApplyOptions, \"value\" | \"style\" | \"type\">\n): CSSProperties | undefined {\n const { style: propStyle, value, type } = options;\n let style = applyBoxVar({\n type,\n style: propStyle,\n media: \"\",\n value,\n });\n if (value && typeof value === \"object\") {\n BREAKPOINTS.forEach((media) => {\n style = applyBoxVar({\n type,\n style,\n media,\n value: value[media],\n });\n });\n }\n return style;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface BoxStyles {\n style?: CSSProperties;\n className: string;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface BoxStylesOptions extends BoxOptions {\n style?: CSSProperties;\n}\n\n/**\n * @see {@link box}\n * @since 6.0.0\n */\nexport function boxStyles(options: BoxStylesOptions): BoxStyles {\n const { style: propStyle, gridColumns, gridItemSize } = options;\n let style = applyBoxVarGroup({\n type: \"columns\",\n style: propStyle,\n value: gridColumns,\n });\n style = applyBoxVarGroup({\n type: \"size\",\n style,\n value: gridItemSize,\n });\n\n return {\n style,\n className: box(options),\n };\n}\n"],"names":["cnb","bem","styles","box","options","className","align","grid","gridName","gridColumns","gridItemSize","gridAutoRows","justify","stacked","reversed","fullWidth","disableGap","disableWrap","disablePadding","phoneColumns","phoneItemSize","tabletColumns","tabletItemSize","desktopColumns","desktopItemSize","largeDesktopColumns","largeDesktopItemSize","phone","tablet","desktop","largeDesktop","isItemSizeEnabled","value","isColumnsEnabled","gap","wrap","padded","column","reverse","applyBoxVar","type","media","style","expectedType","suffix","varName","BREAKPOINTS","applyBoxVarGroup","propStyle","forEach","boxStyles"],"mappings":"AAAA,SAASA,GAAG,QAAQ,YAAY;AAKhC,SAASC,GAAG,QAAQ,kBAAkB;AAEtC,MAAMC,SAASD,IAAI;AAwPnB;;;CAGC,GACD,OAAO,SAASE,IAAIC,UAAsB,CAAC,CAAC;IAC1C,MAAM,EACJC,SAAS,EACTC,QAAQ,EAAE,EACVC,IAAI,EACJC,WAAW,EAAE,EACbC,cAAc,KAAK,EACnBC,YAAY,EACZC,YAAY,EACZC,UAAU,EAAE,EACZC,OAAO,EACPC,QAAQ,EACRC,SAAS,EACTC,UAAU,EACVC,WAAW,EACXC,cAAc,EACf,GAAGd;IACJ,IAAIe;IACJ,IAAIC;IACJ,IAAIC;IACJ,IAAIC;IACJ,IAAIC;IACJ,IAAIC;IACJ,IAAIC;IACJ,IAAIC;IACJ,IAAIjB,eAAe,OAAOA,gBAAgB,UAAU;QACjD,CAAA,EACCkB,OAAOR,YAAY,EACnBS,QAAQP,aAAa,EACrBQ,SAASN,cAAc,EACvBO,cAAcL,mBAAmB,EAClC,GAAGhB,WAAU;IAChB;IACA,IAAIC,gBAAgB,OAAOA,iBAAiB,UAAU;QACnD,CAAA,EACCiB,OAAOP,aAAa,EACpBQ,QAAQN,cAAc,EACtBO,SAASL,eAAe,EACxBM,cAAcJ,oBAAoB,EACnC,GAAGhB,YAAW;IACjB;IAEA,MAAMqB,oBAAoB,CACxBC,QACwBzB,QAAS,CAAA,CAAC,CAACyB,SAASA,UAAU,CAAA;IACxD,MAAMC,mBAAmB,CACvBD,QACwBzB,QAAQ,OAAOyB,UAAU;IAEnD,OAAOhC,IACLE,OAAO;QACLgC,KAAK,CAAClB;QACN,SAASA,eAAe;QACxB,SAASA,eAAe;QACxBmB,MAAM,CAAClB;QACPmB,QAAQ,CAAClB;QACTmB,QAAQxB,WAAW,CAACC;QACpBwB,SAAS,CAACzB,WAAWC;QACrB,kBAAkBD,WAAWC;QAC7B,cAAcC;QACdR;QACA,aAAaA,QAAQE,gBAAgB;QACrC,aAAawB,iBAAiBxB;QAC9B,cAAcF,QAASY,CAAAA,gBAAgBC,aAAY;QACnD,mBACEa,iBAAiBd,iBAAiBY,kBAAkBX;QACtD,eAAeb,QAASc,CAAAA,iBAAiBC,cAAa;QACtD,oBACEW,iBAAiBZ,kBAAkBU,kBAAkBT;QACvD,gBAAgBf,QAASgB,CAAAA,kBAAkBC,eAAc;QACzD,qBACES,iBAAiBV,mBAAmBQ,kBAAkBP;QACxD,sBACEjB,QAASkB,CAAAA,uBAAuBC,oBAAmB;QACrD,2BACEO,iBAAiBR,wBACjBM,kBAAkBL;QACpB,kBAAkBnB,QAAQI;QAC1B,CAACH,SAAS,EAAED,QAAQC;QACpB,eAAeF,UAAU,WAAWA,UAAU;QAC9C,gBAAgBA,UAAU;QAC1B,aAAaA,UAAU,SAASA,UAAU;QAC1C,iBAAiBA,UAAU;QAC3B,kBAAkBM,YAAY;QAC9B,iBAAiBA,YAAY,WAAWA,YAAY;QACpD,eAAeA,YAAY,SAASA,YAAY;QAChD,mBAAmBA,YAAY;QAC/B,kBAAkBA,YAAY;QAC9B,mBAAmBA,YAAY;QAC/B,kBAAkBA,YAAY;IAChC,IACAP;AAEJ;AAkBA;;;CAGC,GACD,SAASkC,YAAYnC,OAAqB;IACxC,MAAM,EAAEoC,IAAI,EAAEC,KAAK,EAAEC,KAAK,EAAEV,KAAK,EAAE,GAAG5B;IACtC,MAAMuC,eAAeH,SAAS,YAAY,WAAW;IACrD,IAAI,OAAOR,UAAUW,cAAc;QACjC,OAAOD;IACT;IAEA,MAAME,SAASJ,SAAS,YAAYA,OAAO;IAC3C,IAAIK,UAAkC,CAAC,UAAU,EAAED,QAAQ;IAC3D,IAAIH,UAAU,gBAAgB;QAC5BI,UAAU,CAAC,wBAAwB,EAAED,QAAQ;IAC/C,OAAO,IAAIH,OAAO;QAChBI,UAAU,CAAC,UAAU,EAAEJ,MAAM,CAAC,EAAEG,QAAQ;IAC1C;IAEA,OAAO;QACL,GAAGF,KAAK;QACR,CAACG,QAAQ,EAAEb;IACb;AACF;AAEA;;;CAGC,GACD,MAAMc,cAAc;IAAC;IAAS;IAAU;IAAW;CAAe;AAElE;;;CAGC,GACD,SAASC,iBACP3C,OAAuD;IAEvD,MAAM,EAAEsC,OAAOM,SAAS,EAAEhB,KAAK,EAAEQ,IAAI,EAAE,GAAGpC;IAC1C,IAAIsC,QAAQH,YAAY;QACtBC;QACAE,OAAOM;QACPP,OAAO;QACPT;IACF;IACA,IAAIA,SAAS,OAAOA,UAAU,UAAU;QACtCc,YAAYG,OAAO,CAAC,CAACR;YACnBC,QAAQH,YAAY;gBAClBC;gBACAE;gBACAD;gBACAT,OAAOA,KAAK,CAACS,MAAM;YACrB;QACF;IACF;IACA,OAAOC;AACT;AAiBA;;;CAGC,GACD,OAAO,SAASQ,UAAU9C,OAAyB;IACjD,MAAM,EAAEsC,OAAOM,SAAS,EAAEvC,WAAW,EAAEC,YAAY,EAAE,GAAGN;IACxD,IAAIsC,QAAQK,iBAAiB;QAC3BP,MAAM;QACNE,OAAOM;QACPhB,OAAOvB;IACT;IACAiC,QAAQK,iBAAiB;QACvBP,MAAM;QACNE;QACAV,OAAOtB;IACT;IAEA,OAAO;QACLgC;QACArC,WAAWF,IAAIC;IACjB;AACF"}
1
+ {"version":3,"sources":["../../src/box/styles.ts"],"sourcesContent":["import { cnb } from \"cnbuilder\";\nimport { type CSSProperties } from \"react\";\n\nimport { type DefinedCSSVariableName } from \"../theme/types.js\";\nimport { type IsEmptyObject, type OverridableStringUnion } from \"../types.js\";\nimport { bem } from \"../utils/bem.js\";\n\nconst styles = bem(\"rmd-box\");\n\ndeclare module \"react\" {\n interface CSSProperties {\n \"--rmd-box-gap\"?: string | number;\n \"--rmd-box-padding\"?: string | number;\n \"--rmd-box-padding-h\"?: string | number;\n \"--rmd-box-padding-v\"?: string | number;\n \"--rmd-box-item-min-size\"?: string | number;\n \"--rmd-box-item-min-height\"?: string | number;\n \"--rmd-box-columns\"?: string | number;\n \"--rmd-box-row-max-height\"?: string;\n \"--rmd-box-auto-rows-height\"?: string;\n \"--rmd-box-phone-columns\"?: number | string;\n \"--rmd-box-phone-item-min-height\"?: number | string;\n \"--rmd-box-phone-item-min-size\"?: number | string;\n \"--rmd-box-tablet-columns\"?: number | string;\n \"--rmd-box-tablet-item-min-size\"?: number | string;\n \"--rmd-box-tablet-item-min-height\"?: number | string;\n \"--rmd-box-desktop-columns\"?: number | string;\n \"--rmd-box-desktop-item-min-size\"?: number | string;\n \"--rmd-box-desktop-item-min-height\"?: number | string;\n \"--rmd-box-large-desktop-columns\"?: number | string;\n \"--rmd-box-large-desktop-item-min-size\"?: number | string;\n \"--rmd-box-large-desktop-item-min-height\"?: number | string;\n }\n}\n\n/** @since 6.2.0 */\nexport interface BoxAlignItemsOverrides {}\n/** @since 6.2.0 */\nexport interface BoxJustifyContentOverrides {}\n/** @since 6.2.0 */\nexport interface BoxGridNameOverrides {}\n\n/**\n * @since 6.0.0\n */\nexport type BoxAlignItems = OverridableStringUnion<\n \"start\" | \"flex-start\" | \"center\" | \"end\" | \"flex-end\" | \"stretch\",\n BoxAlignItemsOverrides\n>;\n\n/**\n * @since 6.0.0\n */\nexport type BoxJustifyContent = OverridableStringUnion<\n BoxAlignItems | \"space-around\" | \"space-between\" | \"space-evenly\",\n BoxJustifyContentOverrides\n>;\n\n/**\n * @since 6.0.0\n */\nexport type BoxFlexDirection = \"row\" | \"column\";\n\n/**\n * @since 6.0.0\n */\nexport type BoxGridColumns = \"fit\" | \"fill\" | number;\n\n/**\n * @since 6.2.0\n */\nexport type BoxGridName =\n IsEmptyObject<BoxGridNameOverrides> extends true\n ? string\n : OverridableStringUnion<never, BoxGridNameOverrides>;\n\n/**\n * @since 6.0.0\n */\nexport type BoxBreakpoints = \"phone\" | \"tablet\" | \"desktop\" | \"largeDesktop\";\n\n/**\n * @since 6.0.0\n */\nexport type BoxGridBreakpointColumns = {\n [key in BoxBreakpoints]?: BoxGridColumns;\n};\n\n/**\n * @since 6.0.0\n */\nexport type BoxGridBreakpointItemSize = {\n [key in BoxBreakpoints]?: string;\n};\n\n/**\n * @since 6.0.0\n */\nexport interface BoxOptions {\n className?: string;\n\n /**\n * Set this to `true` to use `display: grid` instead of `display: flex`.\n *\n * @defaultValue `false`\n */\n grid?: boolean;\n\n /**\n * Set this to `true` to apply `width: 100%`. This can be useful when using\n * nested box layouts.\n *\n * @defaultValue `false`\n */\n fullWidth?: boolean;\n\n /**\n * Set this to `true` to prevent gap between items.\n *\n * @defaultValue `false`\n */\n disableGap?: boolean | \"row\" | \"column\";\n\n /**\n * Set this to `true` to set `flex-wrap: nowrap`.\n *\n * @defaultValue `false`\n */\n disableWrap?: boolean;\n\n /**\n * Set this to `true` to disable the default padding.\n *\n * @defaultValue `false`\n */\n disablePadding?: boolean;\n\n /**\n * This should match one of the names in the `$box-grids` map. So for example:\n *\n * ```scss\n * @use \"react-md\" with (\n * $box-grids: (\n * small: (\n * min: 5rem\n * ),\n * medium: (\n * min: 7rem,\n * gap: 0.5rem,\n * padding: 2rem,\n * ),\n * ),\n * );\n * ```\n *\n * ```ts\n * declare module \"@react-md/core/box/styles\" {\n * interface BoxGridNameOverrides {\n * small: true;\n * medium: true;\n * }\n * }\n * ```\n *\n * The `gridName` should be `\"small\" | \"medium\"`.\n *\n * @defaultValue `\"\"`\n */\n gridName?: BoxGridName;\n\n /**\n * The default behavior for a grid is to automatically determine the number\n * of columns to render by placing as many items as possible with a specific\n * item min-width and the defined gap between items. Once the number of\n * columns has been determined, place the items in the grid and expand to the\n * full column width.\n *\n * This prop is a convenience prop to control how to display items when there\n * are not enough to span all columns without a separate SCSS file.\n *\n * i.e. 3 items were provided but 4 can be rendered.\n *\n * - `\"fit\"` - fill the entire width with columns and stretch columns to fill\n * the remaining space\n * - `\"fill\"` - fill the entire width with columns and add empty columns to\n * fill the remaining space\n * - `number` - ignore the auto layout behavior and specify the number of\n * columns to use instead.\n *\n * If additional responsive behavior is required, an object can be provided\n * to define the column behavior for: phone, tablet, desktop, or\n * largeDesktop.\n *\n * @see {@link gridItemSize} for how the number of columns are determined.\n * @defaultValue `\"fit\"`\n */\n gridColumns?: BoxGridColumns | BoxGridBreakpointColumns;\n\n /**\n * This prop can be used to override the default `--rmd-box-item-min-size`\n * for the grid without a separate SCSS file. Since this is set as a CSS variable,\n * the value must be a number with a unit to work correctly. i.e. `10rem`\n * instead of `160`.\n *\n * If additional responsive behavior is required, an object can be provided\n * to define the column behavior for: phone, tablet, desktop, or\n * largeDesktop.\n *\n * @see {@link https://react-md.dev/sassdoc/box#variables-box-item-min-size}\n */\n gridItemSize?: string | BoxGridBreakpointItemSize;\n\n /**\n * Set this to `true` to enable equal height rows within the grid based\n * on the current `max-height`. This requires the `max-height` to be set\n * on the `Box` either by:\n *\n * - a custom class name that sets `max-height`\n * - `core.box-set-var(auto-rows-height, VALUE)` on the box or a parent element\n *\n * @defaultValue `false`\n */\n gridAutoRows?: boolean;\n\n /**\n * @defaultValue `\"\"`\n */\n align?: BoxAlignItems;\n\n /**\n * The default value is really `center` or whatever the\n * `$box-default-align-items` is set to.\n *\n * @defaultValue `\"\"`\n */\n justify?: BoxJustifyContent;\n\n /**\n * Set this to `true` to set `flex-direction: column` which will stack all\n * items in the box.\n *\n * @defaultValue `false`\n */\n stacked?: boolean;\n\n /**\n * Set this to `true` to reverse the `flex-direction`. i.e.\n * - `flex-direction: row-reverse`\n * - `flex-direction: column-reverse`\n *\n * @defaultValue `false`\n */\n reversed?: boolean;\n}\n\n/**\n * Applies the `className` from the `Box` component to any element.\n *\n * @example Simple Example\n * ```tsx\n * return (\n * <form className={box({ stacked: true})}>\n * {children}\n * </form>\n * );\n * ```\n *\n * If custom media query breakpoints are required, use the {@link boxStyles}\n * function instead which will also set the CSS variables.\n *\n * @see {@link boxStyles}\n * @since 6.0.0\n */\nexport function box(options: BoxOptions = {}): string {\n const {\n className,\n align = \"\",\n grid,\n gridName = \"\",\n gridColumns = \"fit\",\n gridItemSize,\n gridAutoRows,\n justify = \"\",\n stacked,\n reversed,\n fullWidth,\n disableGap,\n disableWrap,\n disablePadding,\n } = options;\n let phoneColumns: BoxGridColumns | undefined;\n let phoneItemSize: string | number | undefined;\n let tabletColumns: BoxGridColumns | undefined;\n let tabletItemSize: string | number | undefined;\n let desktopColumns: BoxGridColumns | undefined;\n let desktopItemSize: string | number | undefined;\n let largeDesktopColumns: BoxGridColumns | undefined;\n let largeDesktopItemSize: string | number | undefined;\n if (gridColumns && typeof gridColumns === \"object\") {\n ({\n phone: phoneColumns,\n tablet: tabletColumns,\n desktop: desktopColumns,\n largeDesktop: largeDesktopColumns,\n } = gridColumns);\n }\n if (gridItemSize && typeof gridItemSize === \"object\") {\n ({\n phone: phoneItemSize,\n tablet: tabletItemSize,\n desktop: desktopItemSize,\n largeDesktop: largeDesktopItemSize,\n } = gridItemSize);\n }\n\n const isItemSizeEnabled = (\n value: string | number | undefined\n ): boolean | undefined => grid && (!!value || value === 0);\n const isColumnsEnabled = (\n value: BoxGridColumns | BoxGridBreakpointColumns | undefined\n ): boolean | undefined => grid && typeof value === \"number\";\n\n return cnb(\n styles({\n gap: !disableGap,\n \"gap-h\": disableGap === \"row\",\n \"gap-v\": disableGap === \"column\",\n wrap: !disableWrap,\n padded: !disablePadding,\n column: stacked && !reversed,\n reverse: !stacked && reversed,\n \"column-reverse\": stacked && reversed,\n \"full-width\": fullWidth,\n grid,\n \"grid-fill\": grid && gridColumns === \"fill\",\n \"grid-size\": isColumnsEnabled(gridColumns),\n \"grid-phone\": grid && (phoneColumns || phoneItemSize),\n \"grid-phone-size\":\n isColumnsEnabled(phoneColumns) || isItemSizeEnabled(phoneItemSize),\n \"grid-tablet\": grid && (tabletColumns || tabletItemSize),\n \"grid-tablet-size\":\n isColumnsEnabled(tabletColumns) || isItemSizeEnabled(tabletItemSize),\n \"grid-desktop\": grid && (desktopColumns || desktopItemSize),\n \"grid-desktop-size\":\n isColumnsEnabled(desktopColumns) || isItemSizeEnabled(desktopItemSize),\n \"grid-large-desktop\":\n grid && (largeDesktopColumns || largeDesktopItemSize),\n \"grid-large-desktop-size\":\n isColumnsEnabled(largeDesktopColumns) ||\n isItemSizeEnabled(largeDesktopItemSize),\n \"grid-auto-rows\": grid && gridAutoRows,\n [gridName]: grid && gridName,\n \"align-start\": align === \"start\" || align === \"flex-start\",\n \"align-center\": align === \"center\",\n \"align-end\": align === \"end\" || align === \"flex-end\",\n \"align-stretch\": align === \"stretch\",\n \"justify-center\": justify === \"center\",\n \"justify-start\": justify === \"start\" || justify === \"flex-start\",\n \"justify-end\": justify === \"end\" || justify === \"flex-end\",\n \"justify-stretch\": justify === \"stretch\",\n \"justify-around\": justify === \"space-around\",\n \"justify-between\": justify === \"space-between\",\n \"justify-evenly\": justify === \"space-evenly\",\n }),\n className\n );\n}\n\n/**\n * @since 6.0.0\n * @internal\n */\ninterface ApplyOptions {\n media: keyof BoxGridBreakpointColumns | \"\";\n style: CSSProperties | undefined;\n type: \"columns\" | \"size\";\n value:\n | BoxGridColumns\n | BoxGridBreakpointColumns\n | string\n | BoxGridBreakpointItemSize\n | undefined;\n}\n\n/**\n * @since 6.0.0\n * @internal\n */\nfunction applyBoxVar(options: ApplyOptions): CSSProperties | undefined {\n const { type, media, style, value } = options;\n const expectedType = type === \"columns\" ? \"number\" : \"string\";\n if (typeof value !== expectedType) {\n return style;\n }\n\n const suffix = type === \"columns\" ? type : \"item-min-size\";\n let varName: DefinedCSSVariableName = `--rmd-box-${suffix}`;\n if (media === \"largeDesktop\") {\n varName = `--rmd-box-large-desktop-${suffix}`;\n } else if (media) {\n varName = `--rmd-box-${media}-${suffix}`;\n }\n\n return {\n ...style,\n [varName]: value,\n };\n}\n\n/**\n * @since 6.0.0\n * @internal\n */\nconst BREAKPOINTS = [\"phone\", \"tablet\", \"desktop\", \"largeDesktop\"] as const;\n\n/**\n * @since 6.0.0\n * @internal\n */\nfunction applyBoxVarGroup(\n options: Pick<ApplyOptions, \"value\" | \"style\" | \"type\">\n): CSSProperties | undefined {\n const { style: propStyle, value, type } = options;\n let style = applyBoxVar({\n type,\n style: propStyle,\n media: \"\",\n value,\n });\n if (value && typeof value === \"object\") {\n BREAKPOINTS.forEach((media) => {\n style = applyBoxVar({\n type,\n style,\n media,\n value: value[media],\n });\n });\n }\n return style;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface BoxStyles {\n style?: CSSProperties;\n className: string;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface BoxStylesOptions extends BoxOptions {\n style?: CSSProperties;\n}\n\n/**\n * Used to apply the styles from the `Box` component to any element by\n * providing a `style` object with CSS variables and a `className`.\n *\n * If you do not need to use\n *\n * @example Simple Example\n * ```tsx\n * return (\n * <form\n * {...boxStyles({\n * grid: true,\n * gridColumns: {\n * phone: 1,\n * desktop: 3,\n * },\n * gridItemSize: {\n * tablet: \"12rem\",\n * },\n * })}\n * >\n * {children}\n * </form>\n * );\n * ```\n *\n * @see {@link box}\n * @since 6.0.0\n */\nexport function boxStyles(options: BoxStylesOptions): BoxStyles {\n const { style: propStyle, gridColumns, gridItemSize } = options;\n let style = applyBoxVarGroup({\n type: \"columns\",\n style: propStyle,\n value: gridColumns,\n });\n style = applyBoxVarGroup({\n type: \"size\",\n style,\n value: gridItemSize,\n });\n\n return {\n style,\n className: box(options),\n };\n}\n"],"names":["cnb","bem","styles","box","options","className","align","grid","gridName","gridColumns","gridItemSize","gridAutoRows","justify","stacked","reversed","fullWidth","disableGap","disableWrap","disablePadding","phoneColumns","phoneItemSize","tabletColumns","tabletItemSize","desktopColumns","desktopItemSize","largeDesktopColumns","largeDesktopItemSize","phone","tablet","desktop","largeDesktop","isItemSizeEnabled","value","isColumnsEnabled","gap","wrap","padded","column","reverse","applyBoxVar","type","media","style","expectedType","suffix","varName","BREAKPOINTS","applyBoxVarGroup","propStyle","forEach","boxStyles"],"mappings":"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"}
@@ -83,7 +83,7 @@ export interface ProvidedFormMessageProps extends Pick<FormMessageProps, "id" |
83
83
  *
84
84
  * @since 2.5.0
85
85
  */
86
- export interface ProvidedTextFieldProps<E extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement> extends TextFieldValidationOptions, TextFieldChangeHandlers<E>, Required<Pick<TextFieldProps, "id" | "name" | "value" | "error">>, Pick<TextFieldProps, "aria-describedby" | "rightAddon"> {
86
+ export interface ProvidedTextFieldProps<E extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement> extends TextFieldValidationOptions, Required<TextFieldChangeHandlers<E>>, Required<Pick<TextFieldProps, "id" | "name" | "value" | "error">>, Pick<TextFieldProps, "aria-describedby" | "rightAddon"> {
87
87
  /**
88
88
  * A ref that must be passed to the `TextField`/`TextArea` so that the custom
89
89
  * validity behavior can work.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/form/useTextField.ts"],"sourcesContent":["\"use client\";\n\nimport {\n type HTMLAttributes,\n type ReactNode,\n type Ref,\n type RefCallback,\n type RefObject,\n useCallback,\n useRef,\n useState,\n} from \"react\";\n\nimport { getIcon } from \"../icon/config.js\";\nimport { type UseStateInitializer, type UseStateSetter } from \"../types.js\";\nimport { useEnsuredId } from \"../useEnsuredId.js\";\nimport { useEnsuredRef } from \"../useEnsuredRef.js\";\nimport { type TextFieldProps } from \"./TextField.js\";\nimport {\n type FormMessageInputLengthCounterProps,\n type FormMessageProps,\n} from \"./types.js\";\nimport { useFormReset } from \"./useFormReset.js\";\nimport {\n type ErrorMessageOptions,\n type GetErrorIcon,\n type GetErrorMessage,\n type IsErrored,\n type TextFieldValidationOptions,\n type TextFieldValidationType,\n defaultGetErrorIcon,\n defaultGetErrorMessage,\n defaultIsErrored,\n} from \"./validation.js\";\n\nconst noop = (): void => {\n // do nothing\n};\n\n/**\n * @since 2.5.0\n * @since 6.0.0 Added the `onInvalid` handler\n */\nexport type TextFieldChangeHandlers<\n E extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement,\n> = Pick<HTMLAttributes<E>, \"onBlur\" | \"onChange\" | \"onInvalid\">;\n\n/** @since 6.0.0 */\nexport interface ErrorChangeHandlerOptions<\n E extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement,\n> {\n /**\n * A ref containing the `TextField` or `TextArea` if you need access to that\n * DOM node for error reporting.\n */\n ref: RefObject<E>;\n\n /**\n * The current name for the `TextField` or `TextArea`.\n */\n name: string;\n\n /**\n * This will be `true` when the `TextField`/`TextArea` has an error.\n */\n error: boolean;\n\n /**\n * The error message returned by {@link GetErrorMessage}/the browser's\n * validation message. This is normally an empty string when the {@link error}\n * state is `false`.\n */\n errorMessage: string;\n}\n\n/**\n * A function that reports the error state changing. A good use-case for this is\n * to keep track of all the errors within your form and keep a submit button\n * disabled until they have been resolved.\n *\n * Example:\n *\n * ```ts\n * const [errors, setErrors] = useState<Record<string, boolean | undefined>>({});\n * const onErrorChange: ErrorChangeHandler = ({ name, error }) =>\n * setErrors((prevErrors) => ({ ...prevErrors, [name]: error }));\n *\n * const invalid = Object.values(errors).some(Boolean);\n *\n * // form implementation is left as an exercise for the reader\n * <Button type=\"submit\" disabled={invalid} onClick={submitForm}>Submit</Button>\n * ```\n *\n * @since 2.5.0\n * @since 6.0.0 Changed to object argument.\n */\nexport type ErrorChangeHandler<\n E extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement,\n> = (options: ErrorChangeHandlerOptions<E>) => void;\n\n/** @since 2.5.6 */\nexport interface TextFieldHookState {\n /**\n * The current value for the `TextField` or `TextArea`.\n */\n value: string;\n\n /**\n * This will be `true` when the `TextField`/`TextArea` has an error.\n */\n error: boolean;\n\n /**\n * The error message returned by {@link GetErrorMessage}/the browser's\n * validation message. This is normally an empty string when the {@link error}\n * state is `false`.\n */\n errorMessage: string;\n}\n\n/**\n * All the props that will be generated and return from the `useTextField` hook\n * that should be passed to a `FormMessage` component.\n *\n * @since 2.5.0\n */\nexport interface ProvidedFormMessageProps\n extends Pick<FormMessageProps, \"id\" | \"theme\" | \"children\">,\n Required<Pick<TextFieldProps, \"error\">>,\n Partial<Pick<FormMessageInputLengthCounterProps, \"length\" | \"maxLength\">> {}\n\n/**\n * All the props that will be generated and returned by the `useTextField` hook\n * that should be passed to a `TextField` component.\n *\n * @since 2.5.0\n */\nexport interface ProvidedTextFieldProps<\n E extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement,\n> extends TextFieldValidationOptions,\n TextFieldChangeHandlers<E>,\n Required<Pick<TextFieldProps, \"id\" | \"name\" | \"value\" | \"error\">>,\n Pick<TextFieldProps, \"aria-describedby\" | \"rightAddon\"> {\n /**\n * A ref that must be passed to the `TextField`/`TextArea` so that the custom\n * validity behavior can work.\n *\n * @since 6.0.0\n */\n ref: RefCallback<E>;\n}\n\n/**\n * @since 2.5.0\n */\nexport interface ProvidedTextFieldMessageProps<\n E extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement,\n> extends ProvidedTextFieldProps<E> {\n /**\n * These props will be defined as long as the `disableMessage` prop is not\n * `true` from the `useTextField` hook.\n */\n messageProps: ProvidedFormMessageProps;\n}\n\n/**\n * @since 6.3.0\n */\nexport interface TextFieldHookComponentOptions<\n E extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement,\n> {\n /**\n * An optional id to use for the `TextField`, `Password`, or `TextArea` that\n * is also used to create an id for the inline help/error messages.\n *\n * @defaultValue `\"text-field-\" + useId()`\n */\n id?: string;\n\n /**\n * A unique name to attach to the `TextField`, `TextArea`, or `Password`\n * component.\n */\n name: string;\n\n /**\n * @since 6.3.0\n */\n form?: string;\n\n /**\n * Boolean if the `FormMessage` should also display a counter for the\n * remaining letters allowed based on the `maxLength`.\n *\n * This will still be considered false if the `maxLength` value is not\n * provided.\n *\n * @defaultValue `false`\n */\n counter?: boolean;\n\n /**\n * An optional help text to display in the `FormMessage` component when there\n * is not an error.\n */\n helpText?: ReactNode;\n\n /**\n * A function used to determine if the `TextField` or `TextArea` is an in\n * errored state.\n *\n * @see {@link defaultIsErrored}\n * @defaultValue `defaultIsErrored`\n */\n isErrored?: IsErrored;\n\n /**\n * An optional error icon used in the {@link getErrorIcon} option.\n *\n * @defaultValue `getIcon(\"error\")`\n */\n errorIcon?: ReactNode;\n\n /**\n * A function used to get the error icon to display at the right of the\n * `TextField` or `TextArea`. The default behavior will only show an icon when\n * the `error` state is `true` and an `errorIcon` option has been provided.\n *\n * @see {@link defaultGetErrorIcon}\n * @defaultValue `defaultGetErrorIcon`\n */\n getErrorIcon?: GetErrorIcon;\n\n /**\n * A function to get and display an error message based on the `TextField` or\n * `TextArea` validity.\n *\n * @see {@link defaultGetErrorMessage}\n * @defaultValue `defaultGetErrorMessage`\n */\n getErrorMessage?: GetErrorMessage;\n\n /**\n * An optional function that will be called whenever the `error` state is\n * changed. This can be used for more complex forms to `disable` the Submit\n * button or anything else if any field has an error.\n *\n * @defaultValue `() => {}`\n */\n onErrorChange?: ErrorChangeHandler<E>;\n\n /**\n * Set to `true` to prevent the state from automatically resetting with a\n * form's `reset` event.\n *\n * @defaultValue `false`\n * @since 6.3.0\n */\n disableReset?: boolean;\n\n /**\n * Set this to `true` to prevent the `errorMessage` from being\n * rendered inline below the `TextField`.\n *\n * @defaultValue `false`\n * @since 6.0.0 Only disables the `errorMessage` behavior so\n * that counters and help text can still be rendered easily.\n */\n disableMessage?: boolean;\n\n /**\n * Boolean if the `maxLength` prop should not be passed to the `TextField`\n * component since it will prevent any additional characters from being\n * entered in the text field which might feel like weird behavior to some\n * users. This should really only be used when the `counter` option is also\n * enabled and rendering along with a `FormMessage` component.\n *\n * @defaultValue `false`\n */\n disableMaxLength?: boolean;\n\n /**\n * @defaultValue `\"recommended\"`\n */\n validationType?: TextFieldValidationType;\n}\n\n/** @since 2.5.6 */\nexport interface TextFieldHookOptions<\n E extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement,\n> extends TextFieldValidationOptions,\n TextFieldHookComponentOptions<E>,\n TextFieldChangeHandlers<E> {\n /**\n * An optional ref that should be merged with the ref returned by this hook.\n * This should really only be used if you are making a custom component using\n * this hook and forwarding refs. If you need a ref to access the `<input>` or\n * `<textarea>` DOM node, you can use the `fieldRef` returned by this hook\n * instead.\n *\n * @example Accessing TextField DOM Node\n * ```tsx\n * import { TextField } from \"@react-md/core/form/TextField\";\n * import { useTextField } from \"@react-md/core/form/useTextField\";\n * import { useEffect } from \"react\";\n * import type { ReactElement } from \"react\";\n *\n * function Example(): ReactElement {\n * const { fieldRef, fieldProps } = useTextField({ name: \"example\" });\n *\n * useEffect(() => {\n * fieldRef.current;\n * // ^ HTMLInputElement | null\n * }, [fieldRef]);\n *\n * return <TextField {...fieldProps} label=\"Example\" />;\n * }\n * ```\n */\n ref?: Ref<E>;\n\n /**\n * This is used internally for the `useNumberField` hook and probably\n * shouldn't be used otherwise. This is just passed into the\n * {@link getErrorMessage} options and is used for additional validation.\n *\n * @defaultValue `false`\n */\n isNumber?: boolean;\n\n /**\n * The default value to use for the `TextField` or `TextArea` one initial\n * render. If you want to manually change the value to something else after\n * the initial render, either change the `key` for the component containing\n * this hook, or use the `setState` function returned from this hook.\n *\n * @defaultValue `\"\"`\n */\n defaultValue?: UseStateInitializer<string>;\n}\n\n/** @since 6.0.0 */\nexport interface TextFieldImplementation<\n E extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement,\n> extends TextFieldHookState {\n fieldRef: RefObject<E>;\n reset: () => void;\n setState: UseStateSetter<Readonly<TextFieldHookState>>;\n fieldProps: ProvidedTextFieldProps<E>;\n}\n\n/** @since 6.0.0 */\nexport interface TextFieldWithMessageImplementation<\n E extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement,\n> extends TextFieldImplementation<E> {\n fieldProps: ProvidedTextFieldMessageProps<E>;\n}\n\n/** @since 6.0.0 */\nexport interface ValidatedTextFieldImplementation<\n E extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement,\n> extends TextFieldImplementation<E> {\n fieldProps: ProvidedTextFieldProps<E> | ProvidedTextFieldMessageProps<E>;\n}\n\n/**\n * If you do not want to display the error messages below the `TextField` and\n * handle error messages separately, set the `disableMessage` option to `true`.\n *\n * @example No Inline Error Messages\n * ```tsx\n * import { type ReactElement } from \"react\";\n * import { TextField } from \"@react-md/core/form/TextField\";\n * import { useTextField } from \"@react-md/core/form/useTextField\";\n *\n * function Example(): ReactElement {\n * const { fieldProps } = useTextField({\n * name: \"example\",\n * disableMessage: true,\n * });\n *\n * return <TextField {...fieldProps} label=\"Example\" />;\n * }\n * ```\n *\n * Look at the other {@link useTextField} override for additional examples.\n *\n * @see {@link https://react-md.dev/components/text-field | TextField Demos}\n * @see {@link https://react-md.dev/hooks/use-text-field | useTextField Demos}\n */\nexport function useTextField<\n E extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement,\n>(\n options: TextFieldHookOptions<E> & { disableMessage: true }\n): TextFieldImplementation<E>;\n\n/**\n * @example Simple Example\n * ```tsx\n * import { type ReactElement } from \"react\";\n * import { TextField } from \"@react-md/core/form/TextField\";\n * import { useTextField } from \"@react-md/core/form/useTextField\";\n *\n * function Example(): ReactElement {\n * const { fieldProps } = useTextField({\n * name: \"example\",\n * });\n *\n * return <TextField {...fieldProps} label=\"Example\" />;\n * }\n * ```\n *\n * @example Inline Counter\n * ```tsx\n * import { type ReactElement } from \"react\";\n * import { TextField } from \"@react-md/core/form/TextField\";\n * import { useTextField } from \"@react-md/core/form/useTextField\";\n *\n * function Example(): ReactElement {\n * const { fieldProps } = useTextField({\n * name: \"example\",\n * counter: true,\n * required: true,\n * maxLength: 20,\n * // this allows the user to type beyond the max length limit and display\n * // an error message. omit or set to `false` to enforce the max length instead\n * disableMaxLength: true,\n * });\n *\n * return <TextField {...fieldProps} label=\"Example\" />;\n * }\n * ```\n *\n * @example Adding Constraints\n * ```tsx\n * import { type ReactElement } from \"react\";\n * import { TextField } from \"@react-md/core/form/TextField\";\n * import { useTextField } from \"@react-md/core/form/useTextField\";\n *\n * function Example(): ReactElement {\n * const { fieldProps } = useTextField({\n * name: \"example\",\n * required: true,\n * pattern: \"^[A-Za-z]+$\",\n * minLength: 4,\n * maxLength: 20,\n * });\n *\n * return <TextField {...fieldProps} label=\"Example\" />;\n * }\n * ```\n *\n * @example Custom Validation\n * ```tsx\n * import { type ReactElement } from \"react\";\n * import { TextField } from \"@react-md/core/form/TextField\";\n * import { useTextField } from \"@react-md/core/form/useTextField\";\n *\n * function Example(): ReactElement {\n * const { fieldProps } = useTextField({\n * name: \"example\",\n * required: true,\n * getErrorMessage(options) {\n * const {\n * value,\n * pattern,\n * required,\n * minLength,\n * maxLength,\n * validity,\n * validationMessage,\n * isNumber,\n * isBlurEvent,\n * validationType,\n * } = options;\n *\n * if (validity.tooLong) {\n * return `No more than ${maxLength} characters.`;\n * }\n *\n * if (validity.tooShort) {\n * return `No more than ${minLength} characters.`;\n * }\n *\n * if (validity.valueMissing) {\n * return \"This value is required!\";\n * }\n *\n * if (value === \"bad value\") {\n * return \"Value cannot be bad value\";\n * }\n *\n * return defaultGetErrorMessage(options);\n * }\n * });\n *\n * return <TextField {...fieldProps} label=\"Example\" />;\n * }\n * ```\n *\n * @see {@link https://react-md.dev/components/text-field | TextField Demos}\n * @see {@link https://react-md.dev/hooks/use-text-field | useTextField Demos}\n * @see https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation\n * @since 2.5.6\n * @since 6.0.0 This hook returns an object instead of an ordered list. Also\n * added the ability to display an inline counter and help text while disabling\n * the error messaging.\n */\nexport function useTextField<\n E extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement,\n>(options: TextFieldHookOptions<E>): TextFieldWithMessageImplementation<E>;\n/**\n * @see {@link https://react-md.dev/components/text-field | TextField Demos}\n * @see {@link https://react-md.dev/hooks/use-text-field | useTextField Demos}\n * @since 6.0.0\n */\nexport function useTextField<\n E extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement,\n>(options: TextFieldHookOptions<E>): ValidatedTextFieldImplementation<E> {\n const {\n id: propId,\n ref: propRef,\n name,\n form,\n defaultValue = \"\",\n isNumber = false,\n required,\n pattern,\n minLength,\n maxLength,\n onBlur = noop,\n onChange = noop,\n onInvalid = noop,\n counter = false,\n helpText,\n disableReset,\n validationType = \"recommended\",\n disableMessage = false,\n disableMaxLength = false,\n errorIcon: propErrorIcon,\n isErrored = defaultIsErrored,\n onErrorChange = noop,\n getErrorIcon = defaultGetErrorIcon,\n getErrorMessage = defaultGetErrorMessage,\n } = options;\n\n const id = useEnsuredId(propId, \"text-field\");\n const messageId = `${id}-message`;\n const [fieldRef, ref] = useEnsuredRef(propRef);\n const [state, setState] = useState<TextFieldHookState>(() => {\n const value =\n typeof defaultValue === \"function\" ? defaultValue() : defaultValue;\n\n return {\n value,\n error: false,\n errorMessage: \"\",\n };\n });\n const { value, error, errorMessage } = state;\n\n // using a `ref` instead of a `useCallback` makes it so the `defaultValue`\n // will always be used once reset.\n const reset = useRef(() => {\n fieldRef.current?.setCustomValidity(\"\");\n setState({ value, error: false, errorMessage: \"\" });\n }).current;\n\n const errored = useRef(error);\n const checkValidity = useCallback(\n (isBlurEvent: boolean) => {\n const field = fieldRef.current;\n if (!field) {\n throw new Error(\"Unable to check validity due to missing ref\");\n }\n\n // need to temporarily set the `maxLength` back so it can be \"verified\"\n // through the validity api\n /* istanbul ignore next */\n if (isBlurEvent && disableMaxLength && typeof maxLength === \"number\") {\n field.maxLength = maxLength;\n }\n\n const { value } = field;\n field.setCustomValidity(\"\");\n field.checkValidity();\n\n // remove the temporarily set `maxLength` attribute after checking the\n // validity\n /* istanbul ignore next */\n if (disableMaxLength && typeof maxLength === \"number\") {\n field.removeAttribute(\"maxLength\");\n }\n\n const options: ErrorMessageOptions = {\n value,\n pattern,\n required,\n minLength,\n maxLength,\n isBlurEvent,\n isNumber,\n validationType,\n validity: field.validity,\n validationMessage: field.validationMessage,\n };\n const errorMessage = getErrorMessage(options);\n const error = isErrored({ ...options, errorMessage });\n\n if (errored.current !== error) {\n errored.current = error;\n onErrorChange({\n ref: fieldRef,\n name,\n error,\n errorMessage,\n });\n }\n\n /* istanbul ignore next */\n if (errorMessage !== field.validationMessage) {\n field.setCustomValidity(errorMessage);\n }\n\n setState((prevState) => {\n if (\n prevState.value === value &&\n prevState.error === error &&\n prevState.errorMessage === errorMessage\n ) {\n return prevState;\n }\n\n return {\n value,\n error,\n errorMessage,\n };\n });\n },\n [\n disableMaxLength,\n fieldRef,\n getErrorMessage,\n isErrored,\n isNumber,\n maxLength,\n minLength,\n name,\n onErrorChange,\n pattern,\n required,\n validationType,\n ]\n );\n\n const errorIcon = getIcon(\"error\", propErrorIcon);\n const fieldProps: ProvidedTextFieldProps<E> & {\n messageProps?: ProvidedFormMessageProps;\n } = {\n id,\n ref,\n name,\n value,\n error,\n required,\n pattern,\n minLength,\n maxLength: disableMaxLength ? undefined : maxLength,\n rightAddon: getErrorIcon({\n error,\n errorIcon,\n errorMessage,\n }),\n onBlur(event) {\n onBlur(event);\n if (event.isPropagationStopped()) {\n return;\n }\n\n checkValidity(true);\n },\n onChange(event) {\n onChange(event);\n if (event.isPropagationStopped()) {\n return;\n }\n\n if (validationType === \"blur\") {\n const { value } = event.currentTarget;\n setState((prevState) => ({\n ...prevState,\n value,\n }));\n return;\n }\n\n checkValidity(false);\n },\n onInvalid(event) {\n onInvalid(event);\n if (\n event.isPropagationStopped() ||\n event.currentTarget === document.activeElement\n ) {\n return;\n }\n\n // this makes it so that if a submit button is clicked in a form, all\n // textfields will gain the error state immediately\n // also need to extract the validationMessage immediately because of the\n // SyntheticEvent behavior in React. By the time the `setState` is called,\n // the event might've been deleted\n const { validationMessage } = event.currentTarget;\n\n setState((prevState) => {\n if (prevState.error) {\n return prevState;\n }\n\n return {\n ...prevState,\n error: true,\n errorMessage: validationMessage,\n };\n });\n },\n };\n\n const isCounter = counter && typeof maxLength === \"number\";\n if (isCounter || helpText || !disableMessage) {\n fieldProps[\"aria-describedby\"] = messageId;\n fieldProps.messageProps = {\n id: messageId,\n error,\n length: counter ? value.length : undefined,\n maxLength: (counter && maxLength) || undefined,\n children: (!disableMessage && errorMessage) || helpText,\n };\n }\n\n useFormReset({\n form,\n onReset: disableReset ? undefined : reset,\n elementRef: fieldRef,\n });\n\n return {\n ...state,\n reset,\n setState,\n fieldRef,\n fieldProps,\n };\n}\n"],"names":["useCallback","useRef","useState","getIcon","useEnsuredId","useEnsuredRef","useFormReset","defaultGetErrorIcon","defaultGetErrorMessage","defaultIsErrored","noop","useTextField","options","id","propId","ref","propRef","name","form","defaultValue","isNumber","required","pattern","minLength","maxLength","onBlur","onChange","onInvalid","counter","helpText","disableReset","validationType","disableMessage","disableMaxLength","errorIcon","propErrorIcon","isErrored","onErrorChange","getErrorIcon","getErrorMessage","messageId","fieldRef","state","setState","value","error","errorMessage","reset","current","setCustomValidity","errored","checkValidity","isBlurEvent","field","Error","removeAttribute","validity","validationMessage","prevState","fieldProps","undefined","rightAddon","event","isPropagationStopped","currentTarget","document","activeElement","isCounter","messageProps","length","children","onReset","elementRef"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/form/useTextField.ts"],"sourcesContent":["\"use client\";\n\nimport {\n type HTMLAttributes,\n type ReactNode,\n type Ref,\n type RefCallback,\n type RefObject,\n useCallback,\n useRef,\n useState,\n} from \"react\";\n\nimport { getIcon } from \"../icon/config.js\";\nimport { type UseStateInitializer, type UseStateSetter } from \"../types.js\";\nimport { useEnsuredId } from \"../useEnsuredId.js\";\nimport { useEnsuredRef } from \"../useEnsuredRef.js\";\nimport { type TextFieldProps } from \"./TextField.js\";\nimport {\n type FormMessageInputLengthCounterProps,\n type FormMessageProps,\n} from \"./types.js\";\nimport { useFormReset } from \"./useFormReset.js\";\nimport {\n type ErrorMessageOptions,\n type GetErrorIcon,\n type GetErrorMessage,\n type IsErrored,\n type TextFieldValidationOptions,\n type TextFieldValidationType,\n defaultGetErrorIcon,\n defaultGetErrorMessage,\n defaultIsErrored,\n} from \"./validation.js\";\n\nconst noop = (): void => {\n // do nothing\n};\n\n/**\n * @since 2.5.0\n * @since 6.0.0 Added the `onInvalid` handler\n */\nexport type TextFieldChangeHandlers<\n E extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement,\n> = Pick<HTMLAttributes<E>, \"onBlur\" | \"onChange\" | \"onInvalid\">;\n\n/** @since 6.0.0 */\nexport interface ErrorChangeHandlerOptions<\n E extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement,\n> {\n /**\n * A ref containing the `TextField` or `TextArea` if you need access to that\n * DOM node for error reporting.\n */\n ref: RefObject<E>;\n\n /**\n * The current name for the `TextField` or `TextArea`.\n */\n name: string;\n\n /**\n * This will be `true` when the `TextField`/`TextArea` has an error.\n */\n error: boolean;\n\n /**\n * The error message returned by {@link GetErrorMessage}/the browser's\n * validation message. This is normally an empty string when the {@link error}\n * state is `false`.\n */\n errorMessage: string;\n}\n\n/**\n * A function that reports the error state changing. A good use-case for this is\n * to keep track of all the errors within your form and keep a submit button\n * disabled until they have been resolved.\n *\n * Example:\n *\n * ```ts\n * const [errors, setErrors] = useState<Record<string, boolean | undefined>>({});\n * const onErrorChange: ErrorChangeHandler = ({ name, error }) =>\n * setErrors((prevErrors) => ({ ...prevErrors, [name]: error }));\n *\n * const invalid = Object.values(errors).some(Boolean);\n *\n * // form implementation is left as an exercise for the reader\n * <Button type=\"submit\" disabled={invalid} onClick={submitForm}>Submit</Button>\n * ```\n *\n * @since 2.5.0\n * @since 6.0.0 Changed to object argument.\n */\nexport type ErrorChangeHandler<\n E extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement,\n> = (options: ErrorChangeHandlerOptions<E>) => void;\n\n/** @since 2.5.6 */\nexport interface TextFieldHookState {\n /**\n * The current value for the `TextField` or `TextArea`.\n */\n value: string;\n\n /**\n * This will be `true` when the `TextField`/`TextArea` has an error.\n */\n error: boolean;\n\n /**\n * The error message returned by {@link GetErrorMessage}/the browser's\n * validation message. This is normally an empty string when the {@link error}\n * state is `false`.\n */\n errorMessage: string;\n}\n\n/**\n * All the props that will be generated and return from the `useTextField` hook\n * that should be passed to a `FormMessage` component.\n *\n * @since 2.5.0\n */\nexport interface ProvidedFormMessageProps\n extends Pick<FormMessageProps, \"id\" | \"theme\" | \"children\">,\n Required<Pick<TextFieldProps, \"error\">>,\n Partial<Pick<FormMessageInputLengthCounterProps, \"length\" | \"maxLength\">> {}\n\n/**\n * All the props that will be generated and returned by the `useTextField` hook\n * that should be passed to a `TextField` component.\n *\n * @since 2.5.0\n */\nexport interface ProvidedTextFieldProps<\n E extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement,\n> extends TextFieldValidationOptions,\n Required<TextFieldChangeHandlers<E>>,\n Required<Pick<TextFieldProps, \"id\" | \"name\" | \"value\" | \"error\">>,\n Pick<TextFieldProps, \"aria-describedby\" | \"rightAddon\"> {\n /**\n * A ref that must be passed to the `TextField`/`TextArea` so that the custom\n * validity behavior can work.\n *\n * @since 6.0.0\n */\n ref: RefCallback<E>;\n}\n\n/**\n * @since 2.5.0\n */\nexport interface ProvidedTextFieldMessageProps<\n E extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement,\n> extends ProvidedTextFieldProps<E> {\n /**\n * These props will be defined as long as the `disableMessage` prop is not\n * `true` from the `useTextField` hook.\n */\n messageProps: ProvidedFormMessageProps;\n}\n\n/**\n * @since 6.3.0\n */\nexport interface TextFieldHookComponentOptions<\n E extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement,\n> {\n /**\n * An optional id to use for the `TextField`, `Password`, or `TextArea` that\n * is also used to create an id for the inline help/error messages.\n *\n * @defaultValue `\"text-field-\" + useId()`\n */\n id?: string;\n\n /**\n * A unique name to attach to the `TextField`, `TextArea`, or `Password`\n * component.\n */\n name: string;\n\n /**\n * @since 6.3.0\n */\n form?: string;\n\n /**\n * Boolean if the `FormMessage` should also display a counter for the\n * remaining letters allowed based on the `maxLength`.\n *\n * This will still be considered false if the `maxLength` value is not\n * provided.\n *\n * @defaultValue `false`\n */\n counter?: boolean;\n\n /**\n * An optional help text to display in the `FormMessage` component when there\n * is not an error.\n */\n helpText?: ReactNode;\n\n /**\n * A function used to determine if the `TextField` or `TextArea` is an in\n * errored state.\n *\n * @see {@link defaultIsErrored}\n * @defaultValue `defaultIsErrored`\n */\n isErrored?: IsErrored;\n\n /**\n * An optional error icon used in the {@link getErrorIcon} option.\n *\n * @defaultValue `getIcon(\"error\")`\n */\n errorIcon?: ReactNode;\n\n /**\n * A function used to get the error icon to display at the right of the\n * `TextField` or `TextArea`. The default behavior will only show an icon when\n * the `error` state is `true` and an `errorIcon` option has been provided.\n *\n * @see {@link defaultGetErrorIcon}\n * @defaultValue `defaultGetErrorIcon`\n */\n getErrorIcon?: GetErrorIcon;\n\n /**\n * A function to get and display an error message based on the `TextField` or\n * `TextArea` validity.\n *\n * @see {@link defaultGetErrorMessage}\n * @defaultValue `defaultGetErrorMessage`\n */\n getErrorMessage?: GetErrorMessage;\n\n /**\n * An optional function that will be called whenever the `error` state is\n * changed. This can be used for more complex forms to `disable` the Submit\n * button or anything else if any field has an error.\n *\n * @defaultValue `() => {}`\n */\n onErrorChange?: ErrorChangeHandler<E>;\n\n /**\n * Set to `true` to prevent the state from automatically resetting with a\n * form's `reset` event.\n *\n * @defaultValue `false`\n * @since 6.3.0\n */\n disableReset?: boolean;\n\n /**\n * Set this to `true` to prevent the `errorMessage` from being\n * rendered inline below the `TextField`.\n *\n * @defaultValue `false`\n * @since 6.0.0 Only disables the `errorMessage` behavior so\n * that counters and help text can still be rendered easily.\n */\n disableMessage?: boolean;\n\n /**\n * Boolean if the `maxLength` prop should not be passed to the `TextField`\n * component since it will prevent any additional characters from being\n * entered in the text field which might feel like weird behavior to some\n * users. This should really only be used when the `counter` option is also\n * enabled and rendering along with a `FormMessage` component.\n *\n * @defaultValue `false`\n */\n disableMaxLength?: boolean;\n\n /**\n * @defaultValue `\"recommended\"`\n */\n validationType?: TextFieldValidationType;\n}\n\n/** @since 2.5.6 */\nexport interface TextFieldHookOptions<\n E extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement,\n> extends TextFieldValidationOptions,\n TextFieldHookComponentOptions<E>,\n TextFieldChangeHandlers<E> {\n /**\n * An optional ref that should be merged with the ref returned by this hook.\n * This should really only be used if you are making a custom component using\n * this hook and forwarding refs. If you need a ref to access the `<input>` or\n * `<textarea>` DOM node, you can use the `fieldRef` returned by this hook\n * instead.\n *\n * @example Accessing TextField DOM Node\n * ```tsx\n * import { TextField } from \"@react-md/core/form/TextField\";\n * import { useTextField } from \"@react-md/core/form/useTextField\";\n * import { useEffect } from \"react\";\n * import type { ReactElement } from \"react\";\n *\n * function Example(): ReactElement {\n * const { fieldRef, fieldProps } = useTextField({ name: \"example\" });\n *\n * useEffect(() => {\n * fieldRef.current;\n * // ^ HTMLInputElement | null\n * }, [fieldRef]);\n *\n * return <TextField {...fieldProps} label=\"Example\" />;\n * }\n * ```\n */\n ref?: Ref<E>;\n\n /**\n * This is used internally for the `useNumberField` hook and probably\n * shouldn't be used otherwise. This is just passed into the\n * {@link getErrorMessage} options and is used for additional validation.\n *\n * @defaultValue `false`\n */\n isNumber?: boolean;\n\n /**\n * The default value to use for the `TextField` or `TextArea` one initial\n * render. If you want to manually change the value to something else after\n * the initial render, either change the `key` for the component containing\n * this hook, or use the `setState` function returned from this hook.\n *\n * @defaultValue `\"\"`\n */\n defaultValue?: UseStateInitializer<string>;\n}\n\n/** @since 6.0.0 */\nexport interface TextFieldImplementation<\n E extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement,\n> extends TextFieldHookState {\n fieldRef: RefObject<E>;\n reset: () => void;\n setState: UseStateSetter<Readonly<TextFieldHookState>>;\n fieldProps: ProvidedTextFieldProps<E>;\n}\n\n/** @since 6.0.0 */\nexport interface TextFieldWithMessageImplementation<\n E extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement,\n> extends TextFieldImplementation<E> {\n fieldProps: ProvidedTextFieldMessageProps<E>;\n}\n\n/** @since 6.0.0 */\nexport interface ValidatedTextFieldImplementation<\n E extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement,\n> extends TextFieldImplementation<E> {\n fieldProps: ProvidedTextFieldProps<E> | ProvidedTextFieldMessageProps<E>;\n}\n\n/**\n * If you do not want to display the error messages below the `TextField` and\n * handle error messages separately, set the `disableMessage` option to `true`.\n *\n * @example No Inline Error Messages\n * ```tsx\n * import { type ReactElement } from \"react\";\n * import { TextField } from \"@react-md/core/form/TextField\";\n * import { useTextField } from \"@react-md/core/form/useTextField\";\n *\n * function Example(): ReactElement {\n * const { fieldProps } = useTextField({\n * name: \"example\",\n * disableMessage: true,\n * });\n *\n * return <TextField {...fieldProps} label=\"Example\" />;\n * }\n * ```\n *\n * Look at the other {@link useTextField} override for additional examples.\n *\n * @see {@link https://react-md.dev/components/text-field | TextField Demos}\n * @see {@link https://react-md.dev/hooks/use-text-field | useTextField Demos}\n */\nexport function useTextField<\n E extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement,\n>(\n options: TextFieldHookOptions<E> & { disableMessage: true }\n): TextFieldImplementation<E>;\n\n/**\n * @example Simple Example\n * ```tsx\n * import { type ReactElement } from \"react\";\n * import { TextField } from \"@react-md/core/form/TextField\";\n * import { useTextField } from \"@react-md/core/form/useTextField\";\n *\n * function Example(): ReactElement {\n * const { fieldProps } = useTextField({\n * name: \"example\",\n * });\n *\n * return <TextField {...fieldProps} label=\"Example\" />;\n * }\n * ```\n *\n * @example Inline Counter\n * ```tsx\n * import { type ReactElement } from \"react\";\n * import { TextField } from \"@react-md/core/form/TextField\";\n * import { useTextField } from \"@react-md/core/form/useTextField\";\n *\n * function Example(): ReactElement {\n * const { fieldProps } = useTextField({\n * name: \"example\",\n * counter: true,\n * required: true,\n * maxLength: 20,\n * // this allows the user to type beyond the max length limit and display\n * // an error message. omit or set to `false` to enforce the max length instead\n * disableMaxLength: true,\n * });\n *\n * return <TextField {...fieldProps} label=\"Example\" />;\n * }\n * ```\n *\n * @example Adding Constraints\n * ```tsx\n * import { type ReactElement } from \"react\";\n * import { TextField } from \"@react-md/core/form/TextField\";\n * import { useTextField } from \"@react-md/core/form/useTextField\";\n *\n * function Example(): ReactElement {\n * const { fieldProps } = useTextField({\n * name: \"example\",\n * required: true,\n * pattern: \"^[A-Za-z]+$\",\n * minLength: 4,\n * maxLength: 20,\n * });\n *\n * return <TextField {...fieldProps} label=\"Example\" />;\n * }\n * ```\n *\n * @example Custom Validation\n * ```tsx\n * import { type ReactElement } from \"react\";\n * import { TextField } from \"@react-md/core/form/TextField\";\n * import { useTextField } from \"@react-md/core/form/useTextField\";\n *\n * function Example(): ReactElement {\n * const { fieldProps } = useTextField({\n * name: \"example\",\n * required: true,\n * getErrorMessage(options) {\n * const {\n * value,\n * pattern,\n * required,\n * minLength,\n * maxLength,\n * validity,\n * validationMessage,\n * isNumber,\n * isBlurEvent,\n * validationType,\n * } = options;\n *\n * if (validity.tooLong) {\n * return `No more than ${maxLength} characters.`;\n * }\n *\n * if (validity.tooShort) {\n * return `No more than ${minLength} characters.`;\n * }\n *\n * if (validity.valueMissing) {\n * return \"This value is required!\";\n * }\n *\n * if (value === \"bad value\") {\n * return \"Value cannot be bad value\";\n * }\n *\n * return defaultGetErrorMessage(options);\n * }\n * });\n *\n * return <TextField {...fieldProps} label=\"Example\" />;\n * }\n * ```\n *\n * @see {@link https://react-md.dev/components/text-field | TextField Demos}\n * @see {@link https://react-md.dev/hooks/use-text-field | useTextField Demos}\n * @see https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation\n * @since 2.5.6\n * @since 6.0.0 This hook returns an object instead of an ordered list. Also\n * added the ability to display an inline counter and help text while disabling\n * the error messaging.\n */\nexport function useTextField<\n E extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement,\n>(options: TextFieldHookOptions<E>): TextFieldWithMessageImplementation<E>;\n/**\n * @see {@link https://react-md.dev/components/text-field | TextField Demos}\n * @see {@link https://react-md.dev/hooks/use-text-field | useTextField Demos}\n * @since 6.0.0\n */\nexport function useTextField<\n E extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement,\n>(options: TextFieldHookOptions<E>): ValidatedTextFieldImplementation<E> {\n const {\n id: propId,\n ref: propRef,\n name,\n form,\n defaultValue = \"\",\n isNumber = false,\n required,\n pattern,\n minLength,\n maxLength,\n onBlur = noop,\n onChange = noop,\n onInvalid = noop,\n counter = false,\n helpText,\n disableReset,\n validationType = \"recommended\",\n disableMessage = false,\n disableMaxLength = false,\n errorIcon: propErrorIcon,\n isErrored = defaultIsErrored,\n onErrorChange = noop,\n getErrorIcon = defaultGetErrorIcon,\n getErrorMessage = defaultGetErrorMessage,\n } = options;\n\n const id = useEnsuredId(propId, \"text-field\");\n const messageId = `${id}-message`;\n const [fieldRef, ref] = useEnsuredRef(propRef);\n const [state, setState] = useState<TextFieldHookState>(() => {\n const value =\n typeof defaultValue === \"function\" ? defaultValue() : defaultValue;\n\n return {\n value,\n error: false,\n errorMessage: \"\",\n };\n });\n const { value, error, errorMessage } = state;\n\n // using a `ref` instead of a `useCallback` makes it so the `defaultValue`\n // will always be used once reset.\n const reset = useRef(() => {\n fieldRef.current?.setCustomValidity(\"\");\n setState({ value, error: false, errorMessage: \"\" });\n }).current;\n\n const errored = useRef(error);\n const checkValidity = useCallback(\n (isBlurEvent: boolean) => {\n const field = fieldRef.current;\n if (!field) {\n throw new Error(\"Unable to check validity due to missing ref\");\n }\n\n // need to temporarily set the `maxLength` back so it can be \"verified\"\n // through the validity api\n /* istanbul ignore next */\n if (isBlurEvent && disableMaxLength && typeof maxLength === \"number\") {\n field.maxLength = maxLength;\n }\n\n const { value } = field;\n field.setCustomValidity(\"\");\n field.checkValidity();\n\n // remove the temporarily set `maxLength` attribute after checking the\n // validity\n /* istanbul ignore next */\n if (disableMaxLength && typeof maxLength === \"number\") {\n field.removeAttribute(\"maxLength\");\n }\n\n const options: ErrorMessageOptions = {\n value,\n pattern,\n required,\n minLength,\n maxLength,\n isBlurEvent,\n isNumber,\n validationType,\n validity: field.validity,\n validationMessage: field.validationMessage,\n };\n const errorMessage = getErrorMessage(options);\n const error = isErrored({ ...options, errorMessage });\n\n if (errored.current !== error) {\n errored.current = error;\n onErrorChange({\n ref: fieldRef,\n name,\n error,\n errorMessage,\n });\n }\n\n /* istanbul ignore next */\n if (errorMessage !== field.validationMessage) {\n field.setCustomValidity(errorMessage);\n }\n\n setState((prevState) => {\n if (\n prevState.value === value &&\n prevState.error === error &&\n prevState.errorMessage === errorMessage\n ) {\n return prevState;\n }\n\n return {\n value,\n error,\n errorMessage,\n };\n });\n },\n [\n disableMaxLength,\n fieldRef,\n getErrorMessage,\n isErrored,\n isNumber,\n maxLength,\n minLength,\n name,\n onErrorChange,\n pattern,\n required,\n validationType,\n ]\n );\n\n const errorIcon = getIcon(\"error\", propErrorIcon);\n const fieldProps: ProvidedTextFieldProps<E> & {\n messageProps?: ProvidedFormMessageProps;\n } = {\n id,\n ref,\n name,\n value,\n error,\n required,\n pattern,\n minLength,\n maxLength: disableMaxLength ? undefined : maxLength,\n rightAddon: getErrorIcon({\n error,\n errorIcon,\n errorMessage,\n }),\n onBlur(event) {\n onBlur(event);\n if (event.isPropagationStopped()) {\n return;\n }\n\n checkValidity(true);\n },\n onChange(event) {\n onChange(event);\n if (event.isPropagationStopped()) {\n return;\n }\n\n if (validationType === \"blur\") {\n const { value } = event.currentTarget;\n setState((prevState) => ({\n ...prevState,\n value,\n }));\n return;\n }\n\n checkValidity(false);\n },\n onInvalid(event) {\n onInvalid(event);\n if (\n event.isPropagationStopped() ||\n event.currentTarget === document.activeElement\n ) {\n return;\n }\n\n // this makes it so that if a submit button is clicked in a form, all\n // textfields will gain the error state immediately\n // also need to extract the validationMessage immediately because of the\n // SyntheticEvent behavior in React. By the time the `setState` is called,\n // the event might've been deleted\n const { validationMessage } = event.currentTarget;\n\n setState((prevState) => {\n if (prevState.error) {\n return prevState;\n }\n\n return {\n ...prevState,\n error: true,\n errorMessage: validationMessage,\n };\n });\n },\n };\n\n const isCounter = counter && typeof maxLength === \"number\";\n if (isCounter || helpText || !disableMessage) {\n fieldProps[\"aria-describedby\"] = messageId;\n fieldProps.messageProps = {\n id: messageId,\n error,\n length: counter ? value.length : undefined,\n maxLength: (counter && maxLength) || undefined,\n children: (!disableMessage && errorMessage) || helpText,\n };\n }\n\n useFormReset({\n form,\n onReset: disableReset ? undefined : reset,\n elementRef: fieldRef,\n });\n\n return {\n ...state,\n reset,\n setState,\n fieldRef,\n fieldProps,\n };\n}\n"],"names":["useCallback","useRef","useState","getIcon","useEnsuredId","useEnsuredRef","useFormReset","defaultGetErrorIcon","defaultGetErrorMessage","defaultIsErrored","noop","useTextField","options","id","propId","ref","propRef","name","form","defaultValue","isNumber","required","pattern","minLength","maxLength","onBlur","onChange","onInvalid","counter","helpText","disableReset","validationType","disableMessage","disableMaxLength","errorIcon","propErrorIcon","isErrored","onErrorChange","getErrorIcon","getErrorMessage","messageId","fieldRef","state","setState","value","error","errorMessage","reset","current","setCustomValidity","errored","checkValidity","isBlurEvent","field","Error","removeAttribute","validity","validationMessage","prevState","fieldProps","undefined","rightAddon","event","isPropagationStopped","currentTarget","document","activeElement","isCounter","messageProps","length","children","onReset","elementRef"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-md/core",
3
- "version": "6.3.3",
3
+ "version": "6.3.4",
4
4
  "description": "The core components and functionality for react-md.",
5
5
  "type": "module",
6
6
  "sass": "./dist/_core.scss",
@@ -80,12 +80,12 @@
80
80
  "devDependencies": {
81
81
  "@jest/globals": "^29.7.0",
82
82
  "@jest/types": "^29.6.3",
83
- "@microsoft/api-extractor": "^7.52.13",
83
+ "@microsoft/api-extractor": "^7.53.0",
84
84
  "@swc/cli": "^0.6.0",
85
85
  "@swc/core": "^1.13.20",
86
86
  "@swc/jest": "^0.2.39",
87
87
  "@testing-library/dom": "^10.4.1",
88
- "@testing-library/jest-dom": "^6.8.0",
88
+ "@testing-library/jest-dom": "^6.9.1",
89
89
  "@testing-library/react": "^16.3.0",
90
90
  "@testing-library/user-event": "^14.6.1",
91
91
  "@trivago/prettier-plugin-sort-imports": "^5.2.2",
@@ -94,7 +94,7 @@
94
94
  "@types/react": "^18.3.12",
95
95
  "@types/react-dom": "^18.3.1",
96
96
  "chokidar": "^4.0.3",
97
- "eslint": "^9.36.0",
97
+ "eslint": "^9.37.0",
98
98
  "filesize": "^11.0.13",
99
99
  "glob": "11.0.3",
100
100
  "jest": "^29.7.0",
package/src/box/styles.ts CHANGED
@@ -254,6 +254,20 @@ export interface BoxOptions {
254
254
  }
255
255
 
256
256
  /**
257
+ * Applies the `className` from the `Box` component to any element.
258
+ *
259
+ * @example Simple Example
260
+ * ```tsx
261
+ * return (
262
+ * <form className={box({ stacked: true})}>
263
+ * {children}
264
+ * </form>
265
+ * );
266
+ * ```
267
+ *
268
+ * If custom media query breakpoints are required, use the {@link boxStyles}
269
+ * function instead which will also set the CSS variables.
270
+ *
257
271
  * @see {@link boxStyles}
258
272
  * @since 6.0.0
259
273
  */
@@ -442,6 +456,31 @@ export interface BoxStylesOptions extends BoxOptions {
442
456
  }
443
457
 
444
458
  /**
459
+ * Used to apply the styles from the `Box` component to any element by
460
+ * providing a `style` object with CSS variables and a `className`.
461
+ *
462
+ * If you do not need to use
463
+ *
464
+ * @example Simple Example
465
+ * ```tsx
466
+ * return (
467
+ * <form
468
+ * {...boxStyles({
469
+ * grid: true,
470
+ * gridColumns: {
471
+ * phone: 1,
472
+ * desktop: 3,
473
+ * },
474
+ * gridItemSize: {
475
+ * tablet: "12rem",
476
+ * },
477
+ * })}
478
+ * >
479
+ * {children}
480
+ * </form>
481
+ * );
482
+ * ```
483
+ *
445
484
  * @see {@link box}
446
485
  * @since 6.0.0
447
486
  */
@@ -138,7 +138,7 @@ export interface ProvidedFormMessageProps
138
138
  export interface ProvidedTextFieldProps<
139
139
  E extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement,
140
140
  > extends TextFieldValidationOptions,
141
- TextFieldChangeHandlers<E>,
141
+ Required<TextFieldChangeHandlers<E>>,
142
142
  Required<Pick<TextFieldProps, "id" | "name" | "value" | "error">>,
143
143
  Pick<TextFieldProps, "aria-describedby" | "rightAddon"> {
144
144
  /**