@lerianstudio/sindarian-ui 2.0.0-beta.10 → 2.0.0-beta.11

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.
@@ -13,7 +13,7 @@
13
13
 
14
14
  @layer components {
15
15
  .input-wrapper {
16
- @apply h-input-wrapper-h border-input-border p-input-wrapper-p relative flex w-full cursor-text items-center rounded-md border transition-[color,box-shadow];
16
+ @apply h-input-wrapper-h border-input-border p-input-wrapper-p relative flex w-full min-w-0 cursor-text items-center rounded-md border transition-[color,box-shadow];
17
17
  }
18
18
 
19
19
  .input-wrapper-focus {
@@ -29,35 +29,79 @@
29
29
  the text jumped the moment you typed; font-medium gave the hint the same
30
30
  presence as the label naming the field.
31
31
 
32
- `w-0` is what lets the input shrink, and it pairs with `flex-1` rather
33
- than fighting it: `flex-1` is `flex: 1 1 0%`, so the flex base size comes
34
- from the basis and the input still grows back to fill its wrapper. What
35
- `w-0` changes is the floor. A flex item never shrinks below its automatic
36
- minimum size, and with no declared width that minimum falls back to the
37
- control's own intrinsic size — 239px for a default `<input>`. Declaring a
38
- width gives the flex algorithm a specified size to use instead, and 0 is
39
- the only value that never floors anything.
40
-
41
- `min-w-0` is NOT the fix here and was measured failing: it lowers this
42
- input's own floor, but the automatic minimum of an ANCESTOR flex item is
43
- computed from this control's min-content contribution, which `min-width`
44
- does not lower. A consumer's own `flex-1` column around the field would
45
- still refuse to shrink.
46
-
47
- There is deliberately NO min-width floor either, and that was measured
32
+ THE CONTRACT, and all three halves of it are measured. A field keeps its
33
+ natural width: nothing here declares one, so the control contributes its
34
+ own intrinsic size and a box sized BY ITS CONTENT — a search box in a
35
+ `flex gap-4` filter bar — comes out as a field. A field fills its box
36
+ instead of overrunning it: `min-w-0` on both boxes drops the automatic
37
+ minimum that used to hold the control at 239px inside a narrower wrapper,
38
+ down to the one width it cannot go under. That floor is arithmetic rather
39
+ than policy — `px-input-px` is 16px a side and the box sizing is
40
+ border-box, so the control is 32px wide carrying nothing at all — and a
41
+ box narrower than that gets the difference painted outside it. Measured at
42
+ 23px on the console's template-builder header, whose `w-48` wrapper is
43
+ squeezed to 18px and which the console repairs with `shrink-0` on that
44
+ wrapper. This package's own `SheetContent side="right"` runs the same
45
+ arithmetic one step earlier: at a 390px viewport `w-2/5 p-12` leaves a
46
+ 59px panel, and the field comes out 41px wide with 9px of text — unusable,
47
+ but inside its box, where 2.0.0-beta.9 painted 189px of it across the
48
+ panel edge. A row that must compress says so on its own flex item, with
49
+ `min-w-0`, and that one token now works.
50
+
51
+ Why no declared width, measured rather than assumed. A declared width
52
+ replaces the control's max-content contribution as well as its min-content
53
+ one, because an `<input>` does not wrap and has only the one intrinsic
54
+ size. `w-0` shipped in 2.0.0-beta.10 and bought a narrow row's compression
55
+ by giving that up: five product-console screens rendered an empty 32px
56
+ chip at every viewport, and a sixth — the template builder's name field —
57
+ did at 390px while keeping 142px of text at 1440px, all of them wrappers
58
+ that had been handed 0px to be as wide as.
59
+ `w-full` buys the same compression without the chip — a percentage
60
+ contributes max-content but zero min-content — and it was the runner-up
61
+ here. It loses on the same filter bar at 390px, where the control is not
62
+ merely sized by its content but squeezed, and it disappears rather than
63
+ letting the bar scroll. Seventeen rule sets were measured against
64
+ seventeen fixtures; none closes all of them.
65
+
66
+ What this one leaves open is `two-up-200`: two fields in a caller's
67
+ `flex-1` columns inside a 200px row, which now overflows by 138px instead
68
+ of compressing. The caller's one token closes it — `min-w-0` on its own
69
+ column, measured at 78px and fitting — and the fixture beside it,
70
+ `two-up-200-caller-min-w-0`, is the guard that keeps that hatch working.
71
+ On 2.0.0-beta.9 the hatch did NOT work: the same row overflowed by 48px
72
+ and the control painted 152px across its neighbour, because the control
73
+ floored at its intrinsic size inside the column that had just agreed to
74
+ compress. That is the difference this rule set makes.
75
+
76
+ `min-width` reaches exactly one box: the one it is declared on. It does
77
+ not lower an ancestor's automatic minimum and it does not lower a
78
+ descendant's — the sentence this comment carried before the fix said so
79
+ and was right. Nothing above contradicts it: the rule works because BOTH
80
+ boxes declare their own, the control's on `.input-base` and the wrapper's
81
+ on `.input-wrapper`, and neither half works alone. Measured: the wrapper's
82
+ alone fails eleven fixtures (`--candidate=wrapper-only-auto`), the
83
+ control's alone fails four (`--candidate=auto-min-w-0`). It is also why
84
+ `two-up-200` stays open above. The caller's `flex-1` column is a third
85
+ box, no declaration in this package reaches it, and only the caller's own
86
+ `min-w-0` lowers it — which is why that row still overflows by 138px.
87
+
88
+ There is deliberately NO positive min-width floor, and that was measured
48
89
  too. A floor here cannot reach the sites that want one: a consumer
49
90
  writing `.input-base` by hand tends to add its own `min-w-0`, which is a
50
91
  `utilities`-layer class and outranks anything this `components`-layer rule
51
92
  set declares. With `min-w-16` added here, the same fixture read 64px wide
52
93
  without that hand-written `min-w-0` and 32px with it. The floor also cost
53
94
  ground elsewhere: two inputs sharing a 120px row went from fitting to
54
- overflowing by 52px. A caller whose field must hold its width says so on
55
- its own wrapper, with `shrink-0`.
95
+ overflowing by 52px, and a floor small enough to survive that row still
96
+ left a squeezed filter bar at 32px of content. A caller whose field must
97
+ hold its width says so on its own wrapper, with `shrink-0`.
56
98
 
57
99
  `scripts/measure-input-shrink.mjs` carries the fixtures and the numbers;
58
- run it when touching this rule set. */
100
+ run it when touching this rule set, and `--candidate=ID` re-measures any
101
+ of the seventeen, or `shipped` for this one, before re-opening the
102
+ trade. */
59
103
  .input-base {
60
- @apply px-input-px text-input-foreground placeholder:text-input-placeholder h-full min-h-0 w-0 flex-1 border-none bg-transparent outline-none focus:ring-0 focus:ring-offset-0;
104
+ @apply px-input-px text-input-foreground placeholder:text-input-placeholder h-full min-h-0 min-w-0 flex-1 border-none bg-transparent outline-none focus:ring-0 focus:ring-offset-0;
61
105
  }
62
106
 
63
107
  .input-disabled {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/enterprise/number-input/index.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAQ9B,MAAM,MAAM,gBAAgB,GAAG;IAC7B,wDAAwD;IACxD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,+EAA+E;IAC/E,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;IAC5C,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,wCAAwC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,yEAAyE;IACzE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,kEAAkE;IAClE,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,8CAA8C;IAC9C,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,sDAAsD;IACtD,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,CAAA;AAmED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAgBpE;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAMxE;AAED,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,aAAa,EACb,GAAG,EACH,GAAG,EACH,IAAQ,EACR,SAAS,EACT,MAAM,EACN,QAAgB,EAChB,EAAE,EACF,SAAS,EACT,WAAW,EACX,YAAY,EAAE,SAAS,EACvB,kBAAkB,EAAE,eAAe,EACpC,EAAE,gBAAgB,qBAgJlB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/enterprise/number-input/index.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAQ9B,MAAM,MAAM,gBAAgB,GAAG;IAC7B,wDAAwD;IACxD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,+EAA+E;IAC/E,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;IAC5C,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,wCAAwC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,yEAAyE;IACzE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,kEAAkE;IAClE,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,8CAA8C;IAC9C,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,sDAAsD;IACtD,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,CAAA;AAmED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAgBpE;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAMxE;AAED,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,aAAa,EACb,GAAG,EACH,GAAG,EACH,IAAQ,EACR,SAAS,EACT,MAAM,EACN,QAAgB,EAChB,EAAE,EACF,SAAS,EACT,WAAW,EACX,YAAY,EAAE,SAAS,EACvB,kBAAkB,EAAE,eAAe,EACpC,EAAE,gBAAgB,qBA2JlB"}
@@ -248,5 +248,5 @@ function NumberInput({ value, onValueChange, min, max, step = 1, precision, loca
248
248
  };
249
249
  const atMin = typeof min === 'number' && value !== null && value <= min;
250
250
  const atMax = typeof max === 'number' && value !== null && value >= max;
251
- return ((0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)('inline-flex items-stretch gap-1', className), children: [(0, jsx_runtime_1.jsx)(icon_button_1.IconButton, { type: "button", variant: "outline", disabled: disabled || atMin, "aria-label": `Decrease${ariaLabel ? ` ${ariaLabel}` : ''}`, onClick: () => stepBy(-1), tabIndex: -1, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Minus, { className: "size-4", "aria-hidden": true }) }), (0, jsx_runtime_1.jsx)("div", { className: "w-28", children: (0, jsx_runtime_1.jsx)(input_1.Input, { id: id, inputMode: "decimal", role: "spinbutton", "aria-valuenow": value ?? undefined, "aria-valuemin": min, "aria-valuemax": max, className: "text-right tabular-nums", value: displayValue, placeholder: placeholder, disabled: disabled, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, onChange: onChange, onKeyDown: onKeyDown, onFocus: onFocus, onBlur: onBlur }) }), (0, jsx_runtime_1.jsx)(icon_button_1.IconButton, { type: "button", variant: "outline", disabled: disabled || atMax, "aria-label": `Increase${ariaLabel ? ` ${ariaLabel}` : ''}`, onClick: () => stepBy(1), tabIndex: -1, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { className: "size-4", "aria-hidden": true }) })] }));
251
+ return ((0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)('inline-flex items-stretch gap-1', className), children: [(0, jsx_runtime_1.jsx)(icon_button_1.IconButton, { className: "shrink-0", type: "button", variant: "outline", disabled: disabled || atMin, "aria-label": `Decrease${ariaLabel ? ` ${ariaLabel}` : ''}`, onClick: () => stepBy(-1), tabIndex: -1, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Minus, { className: "size-4", "aria-hidden": true }) }), (0, jsx_runtime_1.jsx)("div", { className: "w-28 min-w-0", children: (0, jsx_runtime_1.jsx)(input_1.Input, { id: id, inputMode: "decimal", role: "spinbutton", "aria-valuenow": value ?? undefined, "aria-valuemin": min, "aria-valuemax": max, className: "text-right tabular-nums", value: displayValue, placeholder: placeholder, disabled: disabled, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, onChange: onChange, onKeyDown: onKeyDown, onFocus: onFocus, onBlur: onBlur }) }), (0, jsx_runtime_1.jsx)(icon_button_1.IconButton, { className: "shrink-0", type: "button", variant: "outline", disabled: disabled || atMax, "aria-label": `Increase${ariaLabel ? ` ${ariaLabel}` : ''}`, onClick: () => stepBy(1), tabIndex: -1, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { className: "size-4", "aria-hidden": true }) })] }));
252
252
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/enterprise/number-input/index.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAQ9B,MAAM,MAAM,gBAAgB,GAAG;IAC7B,wDAAwD;IACxD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,+EAA+E;IAC/E,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;IAC5C,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,wCAAwC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,yEAAyE;IACzE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,kEAAkE;IAClE,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,8CAA8C;IAC9C,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,sDAAsD;IACtD,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,CAAA;AAmED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAgBpE;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAMxE;AAED,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,aAAa,EACb,GAAG,EACH,GAAG,EACH,IAAQ,EACR,SAAS,EACT,MAAM,EACN,QAAgB,EAChB,EAAE,EACF,SAAS,EACT,WAAW,EACX,YAAY,EAAE,SAAS,EACvB,kBAAkB,EAAE,eAAe,EACpC,EAAE,gBAAgB,qBAgJlB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/enterprise/number-input/index.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAQ9B,MAAM,MAAM,gBAAgB,GAAG;IAC7B,wDAAwD;IACxD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,+EAA+E;IAC/E,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;IAC5C,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,wCAAwC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,yEAAyE;IACzE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,kEAAkE;IAClE,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,8CAA8C;IAC9C,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,sDAAsD;IACtD,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,CAAA;AAmED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAgBpE;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAMxE;AAED,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,aAAa,EACb,GAAG,EACH,GAAG,EACH,IAAQ,EACR,SAAS,EACT,MAAM,EACN,QAAgB,EAChB,EAAE,EACF,SAAS,EACT,WAAW,EACX,YAAY,EAAE,SAAS,EACvB,kBAAkB,EAAE,eAAe,EACpC,EAAE,gBAAgB,qBA2JlB"}
@@ -210,5 +210,5 @@ export function NumberInput({ value, onValueChange, min, max, step = 1, precisio
210
210
  };
211
211
  const atMin = typeof min === 'number' && value !== null && value <= min;
212
212
  const atMax = typeof max === 'number' && value !== null && value >= max;
213
- return (_jsxs("div", { className: cn('inline-flex items-stretch gap-1', className), children: [_jsx(IconButton, { type: "button", variant: "outline", disabled: disabled || atMin, "aria-label": `Decrease${ariaLabel ? ` ${ariaLabel}` : ''}`, onClick: () => stepBy(-1), tabIndex: -1, children: _jsx(Minus, { className: "size-4", "aria-hidden": true }) }), _jsx("div", { className: "w-28", children: _jsx(Input, { id: id, inputMode: "decimal", role: "spinbutton", "aria-valuenow": value ?? undefined, "aria-valuemin": min, "aria-valuemax": max, className: "text-right tabular-nums", value: displayValue, placeholder: placeholder, disabled: disabled, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, onChange: onChange, onKeyDown: onKeyDown, onFocus: onFocus, onBlur: onBlur }) }), _jsx(IconButton, { type: "button", variant: "outline", disabled: disabled || atMax, "aria-label": `Increase${ariaLabel ? ` ${ariaLabel}` : ''}`, onClick: () => stepBy(1), tabIndex: -1, children: _jsx(Plus, { className: "size-4", "aria-hidden": true }) })] }));
213
+ return (_jsxs("div", { className: cn('inline-flex items-stretch gap-1', className), children: [_jsx(IconButton, { className: "shrink-0", type: "button", variant: "outline", disabled: disabled || atMin, "aria-label": `Decrease${ariaLabel ? ` ${ariaLabel}` : ''}`, onClick: () => stepBy(-1), tabIndex: -1, children: _jsx(Minus, { className: "size-4", "aria-hidden": true }) }), _jsx("div", { className: "w-28 min-w-0", children: _jsx(Input, { id: id, inputMode: "decimal", role: "spinbutton", "aria-valuenow": value ?? undefined, "aria-valuemin": min, "aria-valuemax": max, className: "text-right tabular-nums", value: displayValue, placeholder: placeholder, disabled: disabled, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, onChange: onChange, onKeyDown: onKeyDown, onFocus: onFocus, onBlur: onBlur }) }), _jsx(IconButton, { className: "shrink-0", type: "button", variant: "outline", disabled: disabled || atMax, "aria-label": `Increase${ariaLabel ? ` ${ariaLabel}` : ''}`, onClick: () => stepBy(1), tabIndex: -1, children: _jsx(Plus, { className: "size-4", "aria-hidden": true }) })] }));
214
214
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lerianstudio/sindarian-ui",
3
- "version": "2.0.0-beta.10",
3
+ "version": "2.0.0-beta.11",
4
4
  "description": "Sindarian UI - A UI library for Midaz Console",
5
5
  "license": "ISC",
6
6
  "author": {