@recursica/mantine-adapter 0.50.4 → 0.50.6

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.
package/package.json CHANGED
@@ -13,7 +13,7 @@
13
13
  "url": "git+https://github.com/borderux/recursica.git",
14
14
  "directory": "packages/mantine-adapter"
15
15
  },
16
- "version": "0.50.4",
16
+ "version": "0.50.6",
17
17
  "type": "module",
18
18
  "main": "./dist/mantine-adapter.cjs",
19
19
  "module": "./dist/mantine-adapter.js",
@@ -95,3 +95,16 @@ filename text before ever reaching a real control. Switched to `overflow-x: clip
95
95
  establish a scrollport (same visual clipping, still x-axis only per the descender fix above), so
96
96
  it's no longer a focus candidate. This affected every chip with long enough content, not just
97
97
  read-only ones — see `FileUpload`'s own `IMPLEMENTATION_NOTES.md` for how it surfaced there.
98
+
99
+ ### Selected check icon sat to the left of the leading icon instead of replacing it (Matt Massey, 2026-08-28)
100
+
101
+ A checked `Chip` with a custom `icon` (leading icon) rendered both: Mantine's own default check
102
+ icon (via its native `iconWrapper`/`checkIcon` slot, always shown whenever `checked` and its own
103
+ `icon` prop — a different, unrelated slot — is left `undefined`) came first in the DOM, immediately
104
+ followed by this adapter's own `.leadingIcon` span, which we always rendered regardless of checked
105
+ state. mui-adapter's `Chip` never had this problem, since its `icon={checked ? checkIcon : icon}`
106
+ was already a straight swap. Fixed mantine-adapter to match: the custom `.leadingIcon` span now
107
+ only renders when `!checked`, so Mantine's native checkmark overlays/replaces it instead of sitting
108
+ to its left. Required destructuring `checked` explicitly (previously left in `...rest` and passed
109
+ through opaquely) so the render condition and the explicit `checked` prop on `<MantineChip>` stay
110
+ in sync.
@@ -113,3 +113,14 @@ export const WithLeadingIcon: Story = {
113
113
  },
114
114
  render: (args: ChipStoryProps) => <Chip {...args} />,
115
115
  };
116
+
117
+ // Selecting a chip with a leading icon swaps in the checkmark rather than showing both —
118
+ // matches MUI's native behavior of the check icon overlaying the leading icon.
119
+ export const WithLeadingIconSelected: Story = {
120
+ args: {
121
+ ...WithLeadingIcon.args,
122
+ children: "Leading Icon Selected",
123
+ checked: true,
124
+ },
125
+ render: (args: ChipStoryProps) => <Chip {...args} onChange={() => {}} />,
126
+ };
@@ -46,6 +46,7 @@ export const Chip = forwardRef<HTMLInputElement, ChipProps>(function Chip(
46
46
  deleteTabIndex,
47
47
  deleteIconRef,
48
48
  children,
49
+ checked,
49
50
  overStyled = false,
50
51
  wrapperProps,
51
52
  tabIndex,
@@ -97,6 +98,7 @@ export const Chip = forwardRef<HTMLInputElement, ChipProps>(function Chip(
97
98
  <MantineChip
98
99
  ref={ref}
99
100
  {...sanitizedProps}
101
+ checked={checked}
100
102
  className={finalClass}
101
103
  classNames={mergedClassNames}
102
104
  wrapperProps={withCallerOverride(computedWrapperProps, wrapperProps)}
@@ -111,7 +113,10 @@ export const Chip = forwardRef<HTMLInputElement, ChipProps>(function Chip(
111
113
  )}
112
114
  >
113
115
  <span className={styles.innerWrapper}>
114
- {icon && (
116
+ {/* When checked, Mantine's own check icon (rendered in its native iconWrapper slot,
117
+ ahead of this children span) overlays/replaces the leading icon rather than sitting
118
+ next to it — matching mui-adapter's `icon={checked ? checkIcon : icon}` swap. */}
119
+ {icon && !checked && (
115
120
  <span className={styles.leadingIcon} aria-hidden>
116
121
  {icon}
117
122
  </span>
@@ -51,6 +51,7 @@ export const FormControlWrapper = forwardRef<
51
51
  // Generate a reliable ID to map the Label's HTML context down to the component array natively.
52
52
  const generatedId = useId();
53
53
  const id = userProvidedId || `recursica-fc-${generatedId}`;
54
+ const labelId = `${id}-label`;
54
55
 
55
56
  // Evaluate explicit assistive fallbacks ensuring assistiveText correctly prioritizes natively over underlying Mantine configurations!
56
57
  const resolvedAssistive = assistiveText || description;
@@ -67,11 +68,15 @@ export const FormControlWrapper = forwardRef<
67
68
  ? `${rootClass} ${classNameProp}`
68
69
  : rootClass;
69
70
 
70
- // Clone ARIA identifiers directly back down into the nested children wrapper so screen-readers natively hook the external strings
71
+ // Clone ARIA identifiers directly back down into the nested children wrapper so screen-readers natively hook the external strings.
72
+ // `id` is cloned down here too — the label's `htmlFor` below only resolves to the field's
73
+ // native `label.control` when the field itself actually carries this id.
71
74
  const content = React.isValidElement(children)
72
75
  ? React.cloneElement(
73
76
  children as React.ReactElement<Record<string, unknown>>,
74
77
  {
78
+ ...(!(children.props as Record<string, unknown>)["id"] ? { id } : {}),
79
+ "aria-labelledby": labelId,
75
80
  ...(resolvedAssistive &&
76
81
  !(children.props as Record<string, unknown>)["aria-describedby"]
77
82
  ? { "aria-describedby": assistiveId }
@@ -86,7 +91,8 @@ export const FormControlWrapper = forwardRef<
86
91
 
87
92
  const labelNode = label ? (
88
93
  <Label
89
- id={id} // Directly binds ARIA references down
94
+ id={labelId}
95
+ htmlFor={id} // Native label/control association — must not also be set on the label's own id
90
96
  labelAlignment={labelAlignment}
91
97
  labelOptionalText={labelOptionalText}
92
98
  labelWithEditIcon={labelWithEditIcon}