@micha.bigler/ui-core-micha 2.26.2 → 2.26.3

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.
@@ -122,11 +122,15 @@ export function PollCard({ message, canClose: canCloseProp }) {
122
122
  // screenshot of the checkbox/text/percent squeezed onto one tight line
123
123
  // with a thin bar close to the text) -- more internal spacing/a taller
124
124
  // bar, not a wider bubble (MessageBubble.jsx's maxWidth is untouched).
125
- const richLabel = _jsxs(Stack, { sx: { flex: 1, minWidth: 0, opacity: pending.has(option.id) ? 0.6 : 1 }, spacing: 0.75, children: [_jsxs(Stack, { direction: "row", justifyContent: "space-between", children: [_jsx(Typography, { variant: "body2", noWrap: true, children: option.text || option.label }), _jsx(Typography, { variant: "caption", color: "text.secondary", children: resultText })] }), _jsx(LinearProgress, { variant: "determinate", value: percent, sx: { borderRadius: 1, height: 8 }, color: votedByMe ? 'primary' : 'inherit' })] });
125
+ const richLabel = _jsxs(Stack, { sx: { flex: 1, minWidth: 0, opacity: pending.has(option.id) ? 0.6 : 1 }, spacing: 0.75, children: [_jsxs(Stack, { direction: "row", justifyContent: "space-between", spacing: 1, children: [_jsx(Typography, { variant: "body2", noWrap: true, children: option.text || option.label }), _jsx(Typography, { variant: "caption", color: "text.secondary", children: resultText })] }), _jsx(LinearProgress, { variant: "determinate", value: percent, sx: { borderRadius: 1, height: 8 }, color: votedByMe ? 'primary' : 'inherit' })] });
126
126
  return { accessibleLabel, richLabel };
127
127
  };
128
128
  const formControlSx = { width: '100%', m: 0, alignItems: 'flex-start' };
129
- return _jsx(Paper, { variant: "outlined", sx: { p: 1.5 }, "aria-label": t('MessagingPoll.LABEL'), children: _jsxs(Stack, { spacing: 1.5, children: [_jsx(Typography, { variant: "subtitle2", children: poll.question }), poll.allow_multiple
129
+ // MSG-6j: a short question/option set could otherwise pull the whole `MessageBubble`
130
+ // (`width: fit-content`) in tighter than comfortable to read. 260px stays under the
131
+ // bubble's own `maxWidth: min(75%, 680px)` ceiling even at a 375px viewport (75% = 281px)
132
+ // -- verified at that width, not just desktop.
133
+ return _jsx(Paper, { variant: "outlined", sx: { p: 1.5, minWidth: 260 }, "aria-label": t('MessagingPoll.LABEL'), children: _jsxs(Stack, { spacing: 1.5, children: [_jsx(Typography, { variant: "subtitle2", children: poll.question }), poll.allow_multiple
130
134
  ? (poll.options || []).map((option) => {
131
135
  const { accessibleLabel, richLabel } = optionLabel(option);
132
136
  return _jsx(FormControlLabel, { disabled: closed, sx: formControlSx, label: richLabel, control: _jsx(Checkbox, { checked: selected.includes(option.id), inputProps: { 'aria-label': accessibleLabel }, onChange: () => tap(option.id), sx: { pt: 0.25 } }) }, option.id);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@micha.bigler/ui-core-micha",
3
- "version": "2.26.2",
3
+ "version": "2.26.3",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.js",
6
6
  "repository": {
@@ -110,7 +110,13 @@ export function PollCard({ message, canClose: canCloseProp }) {
110
110
  // with a thin bar close to the text) -- more internal spacing/a taller
111
111
  // bar, not a wider bubble (MessageBubble.jsx's maxWidth is untouched).
112
112
  const richLabel = <Stack sx={{ flex: 1, minWidth: 0, opacity: pending.has(option.id) ? 0.6 : 1 }} spacing={0.75}>
113
- <Stack direction="row" justifyContent="space-between">
113
+ {/* MSG-6j: `justifyContent: 'space-between'` only distributes LEFTOVER width -- but
114
+ this row sits inside a `MessageBubble` sized `width: fit-content` around this exact
115
+ content, so there is by construction no leftover width, and space-between alone
116
+ reserved a zero-width gap (the reported bug: label text ran directly into the
117
+ vote-count/percent text). `spacing` adds a real minimum gap via margin, independent
118
+ of justify-content, so the two never touch regardless of available width. */}
119
+ <Stack direction="row" justifyContent="space-between" spacing={1}>
114
120
  <Typography variant="body2" noWrap>{option.text || option.label}</Typography>
115
121
  <Typography variant="caption" color="text.secondary">{resultText}</Typography>
116
122
  </Stack>
@@ -120,7 +126,11 @@ export function PollCard({ message, canClose: canCloseProp }) {
120
126
  };
121
127
  const formControlSx = { width: '100%', m: 0, alignItems: 'flex-start' };
122
128
 
123
- return <Paper variant="outlined" sx={{ p: 1.5 }} aria-label={t('MessagingPoll.LABEL')}><Stack spacing={1.5}>
129
+ // MSG-6j: a short question/option set could otherwise pull the whole `MessageBubble`
130
+ // (`width: fit-content`) in tighter than comfortable to read. 260px stays under the
131
+ // bubble's own `maxWidth: min(75%, 680px)` ceiling even at a 375px viewport (75% = 281px)
132
+ // -- verified at that width, not just desktop.
133
+ return <Paper variant="outlined" sx={{ p: 1.5, minWidth: 260 }} aria-label={t('MessagingPoll.LABEL')}><Stack spacing={1.5}>
124
134
  <Typography variant="subtitle2">{poll.question}</Typography>
125
135
  {poll.allow_multiple
126
136
  ? (poll.options || []).map((option) => {
@@ -122,4 +122,21 @@ describe('poll rendering against the real server contract', () => {
122
122
  screen.getAllByRole('radio').forEach((radio) => expect(radio.disabled).toBe(true));
123
123
  expect(screen.getByText('MessagingPoll.CLOSED')).toBeTruthy();
124
124
  });
125
+
126
+ it('gives the card a minimum width so a short question/option set is not squeezed narrower than comfortable (MSG-6j)', () => {
127
+ render(<MessagingProvider api={baseApi()} active={false}><PollCard message={{ id: 'msg-1', poll: serverPoll() }} /></MessagingProvider>);
128
+ const card = screen.getByLabelText('MessagingPoll.LABEL');
129
+ expect(getComputedStyle(card).minWidth).toBe('260px');
130
+ });
131
+
132
+ it('keeps a real gap between an option label and its vote-count/percent text, not merely space-between with nothing to distribute (MSG-6j)', () => {
133
+ // Regression test for the reported bug: `justifyContent: 'space-between'` alone only
134
+ // distributes LEFTOVER width, and this row sits inside a `width: fit-content` bubble
135
+ // sized around this exact content -- there is never leftover width, so space-between
136
+ // reserved a zero-width gap and the option text ran directly into "2 (100 %)". Must
137
+ // fail if the row's own `spacing` is removed.
138
+ render(<MessagingProvider api={baseApi()} active={false}><PollCard message={{ id: 'msg-1', poll: serverPoll() }} /></MessagingProvider>);
139
+ const resultText = screen.getByText(/MessagingPoll\.OPTION_RESULT.*"count":2.*"percent":67/);
140
+ expect(getComputedStyle(resultText).marginLeft).not.toBe('0px');
141
+ });
125
142
  });