Skip to content

feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#520 item 22) - #555

Merged
Astro-Han merged 3 commits into
mainfrom
feat/22-input-canonical
Jul 6, 2026
Merged

feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#520 item 22)#555
Astro-Han merged 3 commits into
mainfrom
feat/22-input-canonical

Conversation

@Astro-Han

Copy link
Copy Markdown
Contributor

Summary

#22 PR10: collapse the dual Input tracks onto one canonical primitives/input.tsx + primitives/textarea.tsx, retiring the native ui.tsxInput/Textarea.

Why

Refs #22 / #520. The renderer had two parallel Input implementations: the native ui.tsxInput (single <input> + inputClasses, focus-visible:ring-2, used by 44 call sites across 9 settings files) and the Base UI primitives/input.tsxInput (span data-slot="input-control" wrapper + inner Base UI Input + ring-[3px], used by InputGroup). bare-field-chrome-contract pinned the native's data-maka-field-chrome + border-input + ring-2, so retiring the native was not a clean look-preserving swap — it needed inputClasses ported into the Base UI primitive, InputGroup updated to avoid double chrome, and the chrome contract rewritten.

Scope

Changed:

  • primitives/input.tsx now wraps Base UI's Input primitive with maka's inputClasses styling ported as the default chrome. Stays a single <input> (no span wrapper) so caller CSS targeting > input / input:focus-visible still matches. unstyled gives the bare form (bareFieldClasses + data-maka-field-chrome="none") for Field/InputGroup embedding.
  • primitives/textarea.tsx parallel shape: single <textarea> + inputClasses + textarea sizing. Base UI ships no Textarea, so this is a native textarea. Drops the Base UI Field.Control + span wrapper (callers don't use Field).
  • ui.tsxInput, Textarea, inputClasses, bareFieldClasses retired. inputClasses + bareFieldClasses moved into primitives/input.tsx (exported) so number-field keeps its standalone NumberFieldInput chrome.
  • InputGroup: InputGroupInput/InputGroupTextarea already pass unstyled (inner field bare, InputGroup owns the chrome — no double chrome). InputGroup CSS updated to key off data-slot="input"/"textarea" (the single element) instead of the retired span data-slot="input-control"/"textarea-control"; dropped the span-only :contents / :before:hidden rules.
  • index.ts re-exports primitives/input + primitives/textarea as the canonical Input/Textarea; the 44 settings usages keep importing from @maka/ui unchanged.
  • Internal packages/ui imports (composer, plan-reminder-panel, skills-panel) + stories repointed at the primitives.
  • Contracts: new input-canonical-contract (single element, inputClasses token lock, ui.tsx retired, bare-field shape); field-chrome.test rewritten for the unified shape (drops nativeInput/h-8.5/field-sizing-content assertions that pinned the old primitives/input vs ui.tsx divergence); radius-convergeinputClasses tier repointed at primitives/input.tsx.

Not included:

  • PR8 combobox migration (SearchModal + CommandPalette) — separate PR, runtime keyboard interaction risk.

Verification

User-facing impact

None intended. Input/Textarea visuals are preserved by porting inputClasses (min-h-9, border-input, bg-foreground oklch 0.02, px-3 py-2, shadow-sm, focus-visible:ring-2 ring-offset-2) into the Base UI primitive. The DOM changes from a single <input> (ui.tsx) to a single Base UI <input> — still a single <input>, so caller CSS targeting > input keeps matching.

Reviewer notes

  • The single-<input> decision is load-bearing: maka CSS has .settingsRow > input / .settingsField input:focus-visible / .providerEditor input:focus selectors. A span wrapper (the old primitives/input shape) would break the > input direct-child selectors. So the Base UI Input primitive is used directly with inputClasses on it, no span.
  • inputClasses + bareFieldClasses are exported from primitives/input.tsx (not a shared util) because they are the canonical field chrome and number-field is the second consumer of inputClasses for its standalone NumberFieldInput.
  • Textarea drops the Base UI Field.Control wrapper because no caller uses Base UI Field with it; it's a plain native <textarea> with inputClasses. Base UI ships no Textarea component.
  • Commits are independent revert targets; squash on merge.

Checklist

  • Scope matches the PR title and excludes unrelated changes
  • Verification lists commands/results, or explains why they were not run
  • User-facing impact, docs, changelog, migrations, and breaking changes are noted, or marked none
  • Risk, rollback, or review focus is called out for non-trivial changes
  • UI changes include screenshots/video, or explain why not applicable

… Input (#22 PR10)
#22 PR10: collapse the dual Input tracks onto one canonical
primitives/input.tsx + primitives/textarea.tsx, retiring the native ui.tsx
Input/Textarea.
- primitives/input.tsx now wraps Base UI's Input primitive with maka's
inputClasses styling ported as the default chrome. Stays a single <input>
(no span wrapper) so caller CSS targeting `> input` / `input:focus-visible`
still matches. unstyled gives the bare form (bareFieldClasses +
data-maka-field-chrome="none") for Field/InputGroup embedding.
- primitives/textarea.tsx parallel shape: single <textarea> + inputClasses +
textarea sizing. Base UI ships no Textarea, so this is a native textarea.
Drops the Base UI Field.Control + span wrapper (caller doesn't use Field).
- ui.tsx Input, Textarea, inputClasses, bareFieldClasses retired. inputClasses +
bareFieldClasses moved into primitives/input.tsx (exported) so number-field
keeps its standalone NumberFieldInput chrome.
- InputGroup: InputGroupInput/InputGroupTextarea already pass unstyled (inner
field bare, InputGroup owns the chrome — no double chrome). InputGroup CSS
updated to key off data-slot="input"/"textarea" (the single element) instead
of the retired span data-slot="input-control"/"textarea-control"; dropped the
span-only `:contents` / `:before:hidden` rules.
- index.ts re-exports primitives/input + primitives/textarea as the canonical
Input/Textarea; the 44 usages across 9 settings files keep importing from
@maka/ui unchanged.
- Contracts: new input-canonical-contract (single element, inputClasses token
lock, ui.tsx retired, bare-field shape); field-chrome.test rewritten for the
unified shape (drops nativeInput/h-8.5/field-sizing-content assertions that
pinned the old primitives/input vs ui.tsx divergence); radius-converge
inputClasses tier repointed at primitives/input.tsx.
Verification: typecheck clean; @maka/ui test 43/43; @maka/desktop test
2069/2069. Screenshot pixel diff vs main: settings-general and settings-bots
light/dark 1280 AE=0 (pixel-identical, both contain Input). settings-data
364 px (edge); settings-appearance/daily-review ~9-10K px in a 12px right-edge
column (window edge, not input/textarea); settings-memory ~18K px in a large
content block (main-branch composer/sidebar commits #510/#511, not this PR).
…contract
- P2-1: InputGroupInput/Textarea spread props before unstyled and
data-maka-field-chrome so a caller's unstyled={false} cannot re-enable
the inner chrome (would double the border / focus ring). The InputGroup
owns the chrome; the inner control stays bare.
- P2-2: port type="search" WebKit cancel/decoration/results reset into
primitives/input. Main's primitives/input always applied this for
InputGroupInput (search-modal path); the unified Input keeps the
contract for both the @maka/ui Input and InputGroupInput paths.
size/nativeInput/type=file variants audited — no callers in repo
(@maka/ui Input was ui.tsx without these; InputGroupInput never
passed them); removed without a compat layer.
- P3-1: rewrite input-canonical-contract as behavior tests only — no
source regex. Styled/unstyled single element + chrome, InputGroup
force-bare even with unstyled={false}, type="search" webkit reset,
barrel import smoke.
- P3-2: #22 PR10 -> #520 item 22 in comments (the PR流水号 narrative
pointed at the wrong tracker).
The canonical Input/Textarea already force data-maka-field-chrome="none"
when unstyled (the {...props} spread precedes the attribute in both
primitives, so a caller cannot override it). The adapter passing it
explicitly was a no-op. Drop the redundant attribute; keep unstyled.
@Astro-HanAstro-Han changed the title feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#22 PR10)feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#520 item 22)Jul 6, 2026
@Astro-Han
Astro-Han merged commit face525 into mainJul 6, 2026
@Astro-Han
Astro-Han deleted the feat/22-input-canonical branch July 6, 2026 05:37
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#520 item 22) by Astro-Han · Pull Request #555 · apache/maka · GitHub
Skip to content

feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#520 item 22) - #555

Merged
Astro-Han merged 3 commits into
mainfrom
feat/22-input-canonical
Jul 6, 2026
Merged

feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#520 item 22)#555
Astro-Han merged 3 commits into
mainfrom
feat/22-input-canonical

Conversation

@Astro-Han

Copy link
Copy Markdown
Contributor

Summary

#22 PR10: collapse the dual Input tracks onto one canonical primitives/input.tsx + primitives/textarea.tsx, retiring the native ui.tsxInput/Textarea.

Why

Refs #22 / #520. The renderer had two parallel Input implementations: the native ui.tsxInput (single <input> + inputClasses, focus-visible:ring-2, used by 44 call sites across 9 settings files) and the Base UI primitives/input.tsxInput (span data-slot="input-control" wrapper + inner Base UI Input + ring-[3px], used by InputGroup). bare-field-chrome-contract pinned the native's data-maka-field-chrome + border-input + ring-2, so retiring the native was not a clean look-preserving swap — it needed inputClasses ported into the Base UI primitive, InputGroup updated to avoid double chrome, and the chrome contract rewritten.

Scope

Changed:

  • primitives/input.tsx now wraps Base UI's Input primitive with maka's inputClasses styling ported as the default chrome. Stays a single <input> (no span wrapper) so caller CSS targeting > input / input:focus-visible still matches. unstyled gives the bare form (bareFieldClasses + data-maka-field-chrome="none") for Field/InputGroup embedding.
  • primitives/textarea.tsx parallel shape: single <textarea> + inputClasses + textarea sizing. Base UI ships no Textarea, so this is a native textarea. Drops the Base UI Field.Control + span wrapper (callers don't use Field).
  • ui.tsxInput, Textarea, inputClasses, bareFieldClasses retired. inputClasses + bareFieldClasses moved into primitives/input.tsx (exported) so number-field keeps its standalone NumberFieldInput chrome.
  • InputGroup: InputGroupInput/InputGroupTextarea already pass unstyled (inner field bare, InputGroup owns the chrome — no double chrome). InputGroup CSS updated to key off data-slot="input"/"textarea" (the single element) instead of the retired span data-slot="input-control"/"textarea-control"; dropped the span-only :contents / :before:hidden rules.
  • index.ts re-exports primitives/input + primitives/textarea as the canonical Input/Textarea; the 44 settings usages keep importing from @maka/ui unchanged.
  • Internal packages/ui imports (composer, plan-reminder-panel, skills-panel) + stories repointed at the primitives.
  • Contracts: new input-canonical-contract (single element, inputClasses token lock, ui.tsx retired, bare-field shape); field-chrome.test rewritten for the unified shape (drops nativeInput/h-8.5/field-sizing-content assertions that pinned the old primitives/input vs ui.tsx divergence); radius-convergeinputClasses tier repointed at primitives/input.tsx.

Not included:

  • PR8 combobox migration (SearchModal + CommandPalette) — separate PR, runtime keyboard interaction risk.

Verification

User-facing impact

None intended. Input/Textarea visuals are preserved by porting inputClasses (min-h-9, border-input, bg-foreground oklch 0.02, px-3 py-2, shadow-sm, focus-visible:ring-2 ring-offset-2) into the Base UI primitive. The DOM changes from a single <input> (ui.tsx) to a single Base UI <input> — still a single <input>, so caller CSS targeting > input keeps matching.

Reviewer notes

  • The single-<input> decision is load-bearing: maka CSS has .settingsRow > input / .settingsField input:focus-visible / .providerEditor input:focus selectors. A span wrapper (the old primitives/input shape) would break the > input direct-child selectors. So the Base UI Input primitive is used directly with inputClasses on it, no span.
  • inputClasses + bareFieldClasses are exported from primitives/input.tsx (not a shared util) because they are the canonical field chrome and number-field is the second consumer of inputClasses for its standalone NumberFieldInput.
  • Textarea drops the Base UI Field.Control wrapper because no caller uses Base UI Field with it; it's a plain native <textarea> with inputClasses. Base UI ships no Textarea component.
  • Commits are independent revert targets; squash on merge.

Checklist

  • Scope matches the PR title and excludes unrelated changes
  • Verification lists commands/results, or explains why they were not run
  • User-facing impact, docs, changelog, migrations, and breaking changes are noted, or marked none
  • Risk, rollback, or review focus is called out for non-trivial changes
  • UI changes include screenshots/video, or explain why not applicable

… Input (#22 PR10)
#22 PR10: collapse the dual Input tracks onto one canonical
primitives/input.tsx + primitives/textarea.tsx, retiring the native ui.tsx
Input/Textarea.
- primitives/input.tsx now wraps Base UI's Input primitive with maka's
inputClasses styling ported as the default chrome. Stays a single <input>
(no span wrapper) so caller CSS targeting `> input` / `input:focus-visible`
still matches. unstyled gives the bare form (bareFieldClasses +
data-maka-field-chrome="none") for Field/InputGroup embedding.
- primitives/textarea.tsx parallel shape: single <textarea> + inputClasses +
textarea sizing. Base UI ships no Textarea, so this is a native textarea.
Drops the Base UI Field.Control + span wrapper (caller doesn't use Field).
- ui.tsx Input, Textarea, inputClasses, bareFieldClasses retired. inputClasses +
bareFieldClasses moved into primitives/input.tsx (exported) so number-field
keeps its standalone NumberFieldInput chrome.
- InputGroup: InputGroupInput/InputGroupTextarea already pass unstyled (inner
field bare, InputGroup owns the chrome — no double chrome). InputGroup CSS
updated to key off data-slot="input"/"textarea" (the single element) instead
of the retired span data-slot="input-control"/"textarea-control"; dropped the
span-only `:contents` / `:before:hidden` rules.
- index.ts re-exports primitives/input + primitives/textarea as the canonical
Input/Textarea; the 44 usages across 9 settings files keep importing from
@maka/ui unchanged.
- Contracts: new input-canonical-contract (single element, inputClasses token
lock, ui.tsx retired, bare-field shape); field-chrome.test rewritten for the
unified shape (drops nativeInput/h-8.5/field-sizing-content assertions that
pinned the old primitives/input vs ui.tsx divergence); radius-converge
inputClasses tier repointed at primitives/input.tsx.
Verification: typecheck clean; @maka/ui test 43/43; @maka/desktop test
2069/2069. Screenshot pixel diff vs main: settings-general and settings-bots
light/dark 1280 AE=0 (pixel-identical, both contain Input). settings-data
364 px (edge); settings-appearance/daily-review ~9-10K px in a 12px right-edge
column (window edge, not input/textarea); settings-memory ~18K px in a large
content block (main-branch composer/sidebar commits #510/#511, not this PR).
…contract
- P2-1: InputGroupInput/Textarea spread props before unstyled and
data-maka-field-chrome so a caller's unstyled={false} cannot re-enable
the inner chrome (would double the border / focus ring). The InputGroup
owns the chrome; the inner control stays bare.
- P2-2: port type="search" WebKit cancel/decoration/results reset into
primitives/input. Main's primitives/input always applied this for
InputGroupInput (search-modal path); the unified Input keeps the
contract for both the @maka/ui Input and InputGroupInput paths.
size/nativeInput/type=file variants audited — no callers in repo
(@maka/ui Input was ui.tsx without these; InputGroupInput never
passed them); removed without a compat layer.
- P3-1: rewrite input-canonical-contract as behavior tests only — no
source regex. Styled/unstyled single element + chrome, InputGroup
force-bare even with unstyled={false}, type="search" webkit reset,
barrel import smoke.
- P3-2: #22 PR10 -> #520 item 22 in comments (the PR流水号 narrative
pointed at the wrong tracker).
The canonical Input/Textarea already force data-maka-field-chrome="none"
when unstyled (the {...props} spread precedes the attribute in both
primitives, so a caller cannot override it). The adapter passing it
explicitly was a no-op. Drop the redundant attribute; keep unstyled.
@Astro-HanAstro-Han changed the title feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#22 PR10)feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#520 item 22)Jul 6, 2026
@Astro-Han
Astro-Han merged commit face525 into mainJul 6, 2026
@Astro-Han
Astro-Han deleted the feat/22-input-canonical branch July 6, 2026 05:37
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#520 item 22) by Astro-Han · Pull Request #555 · apache/maka · GitHub
Skip to content

feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#520 item 22) - #555

Merged
Astro-Han merged 3 commits into
mainfrom
feat/22-input-canonical
Jul 6, 2026
Merged

feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#520 item 22)#555
Astro-Han merged 3 commits into
mainfrom
feat/22-input-canonical

Conversation

@Astro-Han

Copy link
Copy Markdown
Contributor

Summary

#22 PR10: collapse the dual Input tracks onto one canonical primitives/input.tsx + primitives/textarea.tsx, retiring the native ui.tsxInput/Textarea.

Why

Refs #22 / #520. The renderer had two parallel Input implementations: the native ui.tsxInput (single <input> + inputClasses, focus-visible:ring-2, used by 44 call sites across 9 settings files) and the Base UI primitives/input.tsxInput (span data-slot="input-control" wrapper + inner Base UI Input + ring-[3px], used by InputGroup). bare-field-chrome-contract pinned the native's data-maka-field-chrome + border-input + ring-2, so retiring the native was not a clean look-preserving swap — it needed inputClasses ported into the Base UI primitive, InputGroup updated to avoid double chrome, and the chrome contract rewritten.

Scope

Changed:

  • primitives/input.tsx now wraps Base UI's Input primitive with maka's inputClasses styling ported as the default chrome. Stays a single <input> (no span wrapper) so caller CSS targeting > input / input:focus-visible still matches. unstyled gives the bare form (bareFieldClasses + data-maka-field-chrome="none") for Field/InputGroup embedding.
  • primitives/textarea.tsx parallel shape: single <textarea> + inputClasses + textarea sizing. Base UI ships no Textarea, so this is a native textarea. Drops the Base UI Field.Control + span wrapper (callers don't use Field).
  • ui.tsxInput, Textarea, inputClasses, bareFieldClasses retired. inputClasses + bareFieldClasses moved into primitives/input.tsx (exported) so number-field keeps its standalone NumberFieldInput chrome.
  • InputGroup: InputGroupInput/InputGroupTextarea already pass unstyled (inner field bare, InputGroup owns the chrome — no double chrome). InputGroup CSS updated to key off data-slot="input"/"textarea" (the single element) instead of the retired span data-slot="input-control"/"textarea-control"; dropped the span-only :contents / :before:hidden rules.
  • index.ts re-exports primitives/input + primitives/textarea as the canonical Input/Textarea; the 44 settings usages keep importing from @maka/ui unchanged.
  • Internal packages/ui imports (composer, plan-reminder-panel, skills-panel) + stories repointed at the primitives.
  • Contracts: new input-canonical-contract (single element, inputClasses token lock, ui.tsx retired, bare-field shape); field-chrome.test rewritten for the unified shape (drops nativeInput/h-8.5/field-sizing-content assertions that pinned the old primitives/input vs ui.tsx divergence); radius-convergeinputClasses tier repointed at primitives/input.tsx.

Not included:

  • PR8 combobox migration (SearchModal + CommandPalette) — separate PR, runtime keyboard interaction risk.

Verification

User-facing impact

None intended. Input/Textarea visuals are preserved by porting inputClasses (min-h-9, border-input, bg-foreground oklch 0.02, px-3 py-2, shadow-sm, focus-visible:ring-2 ring-offset-2) into the Base UI primitive. The DOM changes from a single <input> (ui.tsx) to a single Base UI <input> — still a single <input>, so caller CSS targeting > input keeps matching.

Reviewer notes

  • The single-<input> decision is load-bearing: maka CSS has .settingsRow > input / .settingsField input:focus-visible / .providerEditor input:focus selectors. A span wrapper (the old primitives/input shape) would break the > input direct-child selectors. So the Base UI Input primitive is used directly with inputClasses on it, no span.
  • inputClasses + bareFieldClasses are exported from primitives/input.tsx (not a shared util) because they are the canonical field chrome and number-field is the second consumer of inputClasses for its standalone NumberFieldInput.
  • Textarea drops the Base UI Field.Control wrapper because no caller uses Base UI Field with it; it's a plain native <textarea> with inputClasses. Base UI ships no Textarea component.
  • Commits are independent revert targets; squash on merge.

Checklist

  • Scope matches the PR title and excludes unrelated changes
  • Verification lists commands/results, or explains why they were not run
  • User-facing impact, docs, changelog, migrations, and breaking changes are noted, or marked none
  • Risk, rollback, or review focus is called out for non-trivial changes
  • UI changes include screenshots/video, or explain why not applicable

… Input (#22 PR10)
#22 PR10: collapse the dual Input tracks onto one canonical
primitives/input.tsx + primitives/textarea.tsx, retiring the native ui.tsx
Input/Textarea.
- primitives/input.tsx now wraps Base UI's Input primitive with maka's
inputClasses styling ported as the default chrome. Stays a single <input>
(no span wrapper) so caller CSS targeting `> input` / `input:focus-visible`
still matches. unstyled gives the bare form (bareFieldClasses +
data-maka-field-chrome="none") for Field/InputGroup embedding.
- primitives/textarea.tsx parallel shape: single <textarea> + inputClasses +
textarea sizing. Base UI ships no Textarea, so this is a native textarea.
Drops the Base UI Field.Control + span wrapper (caller doesn't use Field).
- ui.tsx Input, Textarea, inputClasses, bareFieldClasses retired. inputClasses +
bareFieldClasses moved into primitives/input.tsx (exported) so number-field
keeps its standalone NumberFieldInput chrome.
- InputGroup: InputGroupInput/InputGroupTextarea already pass unstyled (inner
field bare, InputGroup owns the chrome — no double chrome). InputGroup CSS
updated to key off data-slot="input"/"textarea" (the single element) instead
of the retired span data-slot="input-control"/"textarea-control"; dropped the
span-only `:contents` / `:before:hidden` rules.
- index.ts re-exports primitives/input + primitives/textarea as the canonical
Input/Textarea; the 44 usages across 9 settings files keep importing from
@maka/ui unchanged.
- Contracts: new input-canonical-contract (single element, inputClasses token
lock, ui.tsx retired, bare-field shape); field-chrome.test rewritten for the
unified shape (drops nativeInput/h-8.5/field-sizing-content assertions that
pinned the old primitives/input vs ui.tsx divergence); radius-converge
inputClasses tier repointed at primitives/input.tsx.
Verification: typecheck clean; @maka/ui test 43/43; @maka/desktop test
2069/2069. Screenshot pixel diff vs main: settings-general and settings-bots
light/dark 1280 AE=0 (pixel-identical, both contain Input). settings-data
364 px (edge); settings-appearance/daily-review ~9-10K px in a 12px right-edge
column (window edge, not input/textarea); settings-memory ~18K px in a large
content block (main-branch composer/sidebar commits #510/#511, not this PR).
…contract
- P2-1: InputGroupInput/Textarea spread props before unstyled and
data-maka-field-chrome so a caller's unstyled={false} cannot re-enable
the inner chrome (would double the border / focus ring). The InputGroup
owns the chrome; the inner control stays bare.
- P2-2: port type="search" WebKit cancel/decoration/results reset into
primitives/input. Main's primitives/input always applied this for
InputGroupInput (search-modal path); the unified Input keeps the
contract for both the @maka/ui Input and InputGroupInput paths.
size/nativeInput/type=file variants audited — no callers in repo
(@maka/ui Input was ui.tsx without these; InputGroupInput never
passed them); removed without a compat layer.
- P3-1: rewrite input-canonical-contract as behavior tests only — no
source regex. Styled/unstyled single element + chrome, InputGroup
force-bare even with unstyled={false}, type="search" webkit reset,
barrel import smoke.
- P3-2: #22 PR10 -> #520 item 22 in comments (the PR流水号 narrative
pointed at the wrong tracker).
The canonical Input/Textarea already force data-maka-field-chrome="none"
when unstyled (the {...props} spread precedes the attribute in both
primitives, so a caller cannot override it). The adapter passing it
explicitly was a no-op. Drop the redundant attribute; keep unstyled.
@Astro-HanAstro-Han changed the title feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#22 PR10)feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#520 item 22)Jul 6, 2026
@Astro-Han
Astro-Han merged commit face525 into mainJul 6, 2026
@Astro-Han
Astro-Han deleted the feat/22-input-canonical branch July 6, 2026 05:37
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#520 item 22) by Astro-Han · Pull Request #555 · apache/maka · GitHub
Skip to content

feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#520 item 22) - #555

Merged
Astro-Han merged 3 commits into
mainfrom
feat/22-input-canonical
Jul 6, 2026
Merged

feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#520 item 22)#555
Astro-Han merged 3 commits into
mainfrom
feat/22-input-canonical

Conversation

@Astro-Han

Copy link
Copy Markdown
Contributor

Summary

#22 PR10: collapse the dual Input tracks onto one canonical primitives/input.tsx + primitives/textarea.tsx, retiring the native ui.tsxInput/Textarea.

Why

Refs #22 / #520. The renderer had two parallel Input implementations: the native ui.tsxInput (single <input> + inputClasses, focus-visible:ring-2, used by 44 call sites across 9 settings files) and the Base UI primitives/input.tsxInput (span data-slot="input-control" wrapper + inner Base UI Input + ring-[3px], used by InputGroup). bare-field-chrome-contract pinned the native's data-maka-field-chrome + border-input + ring-2, so retiring the native was not a clean look-preserving swap — it needed inputClasses ported into the Base UI primitive, InputGroup updated to avoid double chrome, and the chrome contract rewritten.

Scope

Changed:

  • primitives/input.tsx now wraps Base UI's Input primitive with maka's inputClasses styling ported as the default chrome. Stays a single <input> (no span wrapper) so caller CSS targeting > input / input:focus-visible still matches. unstyled gives the bare form (bareFieldClasses + data-maka-field-chrome="none") for Field/InputGroup embedding.
  • primitives/textarea.tsx parallel shape: single <textarea> + inputClasses + textarea sizing. Base UI ships no Textarea, so this is a native textarea. Drops the Base UI Field.Control + span wrapper (callers don't use Field).
  • ui.tsxInput, Textarea, inputClasses, bareFieldClasses retired. inputClasses + bareFieldClasses moved into primitives/input.tsx (exported) so number-field keeps its standalone NumberFieldInput chrome.
  • InputGroup: InputGroupInput/InputGroupTextarea already pass unstyled (inner field bare, InputGroup owns the chrome — no double chrome). InputGroup CSS updated to key off data-slot="input"/"textarea" (the single element) instead of the retired span data-slot="input-control"/"textarea-control"; dropped the span-only :contents / :before:hidden rules.
  • index.ts re-exports primitives/input + primitives/textarea as the canonical Input/Textarea; the 44 settings usages keep importing from @maka/ui unchanged.
  • Internal packages/ui imports (composer, plan-reminder-panel, skills-panel) + stories repointed at the primitives.
  • Contracts: new input-canonical-contract (single element, inputClasses token lock, ui.tsx retired, bare-field shape); field-chrome.test rewritten for the unified shape (drops nativeInput/h-8.5/field-sizing-content assertions that pinned the old primitives/input vs ui.tsx divergence); radius-convergeinputClasses tier repointed at primitives/input.tsx.

Not included:

  • PR8 combobox migration (SearchModal + CommandPalette) — separate PR, runtime keyboard interaction risk.

Verification

User-facing impact

None intended. Input/Textarea visuals are preserved by porting inputClasses (min-h-9, border-input, bg-foreground oklch 0.02, px-3 py-2, shadow-sm, focus-visible:ring-2 ring-offset-2) into the Base UI primitive. The DOM changes from a single <input> (ui.tsx) to a single Base UI <input> — still a single <input>, so caller CSS targeting > input keeps matching.

Reviewer notes

  • The single-<input> decision is load-bearing: maka CSS has .settingsRow > input / .settingsField input:focus-visible / .providerEditor input:focus selectors. A span wrapper (the old primitives/input shape) would break the > input direct-child selectors. So the Base UI Input primitive is used directly with inputClasses on it, no span.
  • inputClasses + bareFieldClasses are exported from primitives/input.tsx (not a shared util) because they are the canonical field chrome and number-field is the second consumer of inputClasses for its standalone NumberFieldInput.
  • Textarea drops the Base UI Field.Control wrapper because no caller uses Base UI Field with it; it's a plain native <textarea> with inputClasses. Base UI ships no Textarea component.
  • Commits are independent revert targets; squash on merge.

Checklist

  • Scope matches the PR title and excludes unrelated changes
  • Verification lists commands/results, or explains why they were not run
  • User-facing impact, docs, changelog, migrations, and breaking changes are noted, or marked none
  • Risk, rollback, or review focus is called out for non-trivial changes
  • UI changes include screenshots/video, or explain why not applicable

… Input (#22 PR10)
#22 PR10: collapse the dual Input tracks onto one canonical
primitives/input.tsx + primitives/textarea.tsx, retiring the native ui.tsx
Input/Textarea.
- primitives/input.tsx now wraps Base UI's Input primitive with maka's
inputClasses styling ported as the default chrome. Stays a single <input>
(no span wrapper) so caller CSS targeting `> input` / `input:focus-visible`
still matches. unstyled gives the bare form (bareFieldClasses +
data-maka-field-chrome="none") for Field/InputGroup embedding.
- primitives/textarea.tsx parallel shape: single <textarea> + inputClasses +
textarea sizing. Base UI ships no Textarea, so this is a native textarea.
Drops the Base UI Field.Control + span wrapper (caller doesn't use Field).
- ui.tsx Input, Textarea, inputClasses, bareFieldClasses retired. inputClasses +
bareFieldClasses moved into primitives/input.tsx (exported) so number-field
keeps its standalone NumberFieldInput chrome.
- InputGroup: InputGroupInput/InputGroupTextarea already pass unstyled (inner
field bare, InputGroup owns the chrome — no double chrome). InputGroup CSS
updated to key off data-slot="input"/"textarea" (the single element) instead
of the retired span data-slot="input-control"/"textarea-control"; dropped the
span-only `:contents` / `:before:hidden` rules.
- index.ts re-exports primitives/input + primitives/textarea as the canonical
Input/Textarea; the 44 usages across 9 settings files keep importing from
@maka/ui unchanged.
- Contracts: new input-canonical-contract (single element, inputClasses token
lock, ui.tsx retired, bare-field shape); field-chrome.test rewritten for the
unified shape (drops nativeInput/h-8.5/field-sizing-content assertions that
pinned the old primitives/input vs ui.tsx divergence); radius-converge
inputClasses tier repointed at primitives/input.tsx.
Verification: typecheck clean; @maka/ui test 43/43; @maka/desktop test
2069/2069. Screenshot pixel diff vs main: settings-general and settings-bots
light/dark 1280 AE=0 (pixel-identical, both contain Input). settings-data
364 px (edge); settings-appearance/daily-review ~9-10K px in a 12px right-edge
column (window edge, not input/textarea); settings-memory ~18K px in a large
content block (main-branch composer/sidebar commits #510/#511, not this PR).
…contract
- P2-1: InputGroupInput/Textarea spread props before unstyled and
data-maka-field-chrome so a caller's unstyled={false} cannot re-enable
the inner chrome (would double the border / focus ring). The InputGroup
owns the chrome; the inner control stays bare.
- P2-2: port type="search" WebKit cancel/decoration/results reset into
primitives/input. Main's primitives/input always applied this for
InputGroupInput (search-modal path); the unified Input keeps the
contract for both the @maka/ui Input and InputGroupInput paths.
size/nativeInput/type=file variants audited — no callers in repo
(@maka/ui Input was ui.tsx without these; InputGroupInput never
passed them); removed without a compat layer.
- P3-1: rewrite input-canonical-contract as behavior tests only — no
source regex. Styled/unstyled single element + chrome, InputGroup
force-bare even with unstyled={false}, type="search" webkit reset,
barrel import smoke.
- P3-2: #22 PR10 -> #520 item 22 in comments (the PR流水号 narrative
pointed at the wrong tracker).
The canonical Input/Textarea already force data-maka-field-chrome="none"
when unstyled (the {...props} spread precedes the attribute in both
primitives, so a caller cannot override it). The adapter passing it
explicitly was a no-op. Drop the redundant attribute; keep unstyled.
@Astro-HanAstro-Han changed the title feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#22 PR10)feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#520 item 22)Jul 6, 2026
@Astro-Han
Astro-Han merged commit face525 into mainJul 6, 2026
@Astro-Han
Astro-Han deleted the feat/22-input-canonical branch July 6, 2026 05:37
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#520 item 22) by Astro-Han · Pull Request #555 · apache/maka · GitHub
Skip to content

feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#520 item 22) - #555

Merged
Astro-Han merged 3 commits into
mainfrom
feat/22-input-canonical
Jul 6, 2026
Merged

feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#520 item 22)#555
Astro-Han merged 3 commits into
mainfrom
feat/22-input-canonical

Conversation

@Astro-Han

Copy link
Copy Markdown
Contributor

Summary

#22 PR10: collapse the dual Input tracks onto one canonical primitives/input.tsx + primitives/textarea.tsx, retiring the native ui.tsxInput/Textarea.

Why

Refs #22 / #520. The renderer had two parallel Input implementations: the native ui.tsxInput (single <input> + inputClasses, focus-visible:ring-2, used by 44 call sites across 9 settings files) and the Base UI primitives/input.tsxInput (span data-slot="input-control" wrapper + inner Base UI Input + ring-[3px], used by InputGroup). bare-field-chrome-contract pinned the native's data-maka-field-chrome + border-input + ring-2, so retiring the native was not a clean look-preserving swap — it needed inputClasses ported into the Base UI primitive, InputGroup updated to avoid double chrome, and the chrome contract rewritten.

Scope

Changed:

  • primitives/input.tsx now wraps Base UI's Input primitive with maka's inputClasses styling ported as the default chrome. Stays a single <input> (no span wrapper) so caller CSS targeting > input / input:focus-visible still matches. unstyled gives the bare form (bareFieldClasses + data-maka-field-chrome="none") for Field/InputGroup embedding.
  • primitives/textarea.tsx parallel shape: single <textarea> + inputClasses + textarea sizing. Base UI ships no Textarea, so this is a native textarea. Drops the Base UI Field.Control + span wrapper (callers don't use Field).
  • ui.tsxInput, Textarea, inputClasses, bareFieldClasses retired. inputClasses + bareFieldClasses moved into primitives/input.tsx (exported) so number-field keeps its standalone NumberFieldInput chrome.
  • InputGroup: InputGroupInput/InputGroupTextarea already pass unstyled (inner field bare, InputGroup owns the chrome — no double chrome). InputGroup CSS updated to key off data-slot="input"/"textarea" (the single element) instead of the retired span data-slot="input-control"/"textarea-control"; dropped the span-only :contents / :before:hidden rules.
  • index.ts re-exports primitives/input + primitives/textarea as the canonical Input/Textarea; the 44 settings usages keep importing from @maka/ui unchanged.
  • Internal packages/ui imports (composer, plan-reminder-panel, skills-panel) + stories repointed at the primitives.
  • Contracts: new input-canonical-contract (single element, inputClasses token lock, ui.tsx retired, bare-field shape); field-chrome.test rewritten for the unified shape (drops nativeInput/h-8.5/field-sizing-content assertions that pinned the old primitives/input vs ui.tsx divergence); radius-convergeinputClasses tier repointed at primitives/input.tsx.

Not included:

  • PR8 combobox migration (SearchModal + CommandPalette) — separate PR, runtime keyboard interaction risk.

Verification

User-facing impact

None intended. Input/Textarea visuals are preserved by porting inputClasses (min-h-9, border-input, bg-foreground oklch 0.02, px-3 py-2, shadow-sm, focus-visible:ring-2 ring-offset-2) into the Base UI primitive. The DOM changes from a single <input> (ui.tsx) to a single Base UI <input> — still a single <input>, so caller CSS targeting > input keeps matching.

Reviewer notes

  • The single-<input> decision is load-bearing: maka CSS has .settingsRow > input / .settingsField input:focus-visible / .providerEditor input:focus selectors. A span wrapper (the old primitives/input shape) would break the > input direct-child selectors. So the Base UI Input primitive is used directly with inputClasses on it, no span.
  • inputClasses + bareFieldClasses are exported from primitives/input.tsx (not a shared util) because they are the canonical field chrome and number-field is the second consumer of inputClasses for its standalone NumberFieldInput.
  • Textarea drops the Base UI Field.Control wrapper because no caller uses Base UI Field with it; it's a plain native <textarea> with inputClasses. Base UI ships no Textarea component.
  • Commits are independent revert targets; squash on merge.

Checklist

  • Scope matches the PR title and excludes unrelated changes
  • Verification lists commands/results, or explains why they were not run
  • User-facing impact, docs, changelog, migrations, and breaking changes are noted, or marked none
  • Risk, rollback, or review focus is called out for non-trivial changes
  • UI changes include screenshots/video, or explain why not applicable

… Input (#22 PR10)
#22 PR10: collapse the dual Input tracks onto one canonical
primitives/input.tsx + primitives/textarea.tsx, retiring the native ui.tsx
Input/Textarea.
- primitives/input.tsx now wraps Base UI's Input primitive with maka's
inputClasses styling ported as the default chrome. Stays a single <input>
(no span wrapper) so caller CSS targeting `> input` / `input:focus-visible`
still matches. unstyled gives the bare form (bareFieldClasses +
data-maka-field-chrome="none") for Field/InputGroup embedding.
- primitives/textarea.tsx parallel shape: single <textarea> + inputClasses +
textarea sizing. Base UI ships no Textarea, so this is a native textarea.
Drops the Base UI Field.Control + span wrapper (caller doesn't use Field).
- ui.tsx Input, Textarea, inputClasses, bareFieldClasses retired. inputClasses +
bareFieldClasses moved into primitives/input.tsx (exported) so number-field
keeps its standalone NumberFieldInput chrome.
- InputGroup: InputGroupInput/InputGroupTextarea already pass unstyled (inner
field bare, InputGroup owns the chrome — no double chrome). InputGroup CSS
updated to key off data-slot="input"/"textarea" (the single element) instead
of the retired span data-slot="input-control"/"textarea-control"; dropped the
span-only `:contents` / `:before:hidden` rules.
- index.ts re-exports primitives/input + primitives/textarea as the canonical
Input/Textarea; the 44 usages across 9 settings files keep importing from
@maka/ui unchanged.
- Contracts: new input-canonical-contract (single element, inputClasses token
lock, ui.tsx retired, bare-field shape); field-chrome.test rewritten for the
unified shape (drops nativeInput/h-8.5/field-sizing-content assertions that
pinned the old primitives/input vs ui.tsx divergence); radius-converge
inputClasses tier repointed at primitives/input.tsx.
Verification: typecheck clean; @maka/ui test 43/43; @maka/desktop test
2069/2069. Screenshot pixel diff vs main: settings-general and settings-bots
light/dark 1280 AE=0 (pixel-identical, both contain Input). settings-data
364 px (edge); settings-appearance/daily-review ~9-10K px in a 12px right-edge
column (window edge, not input/textarea); settings-memory ~18K px in a large
content block (main-branch composer/sidebar commits #510/#511, not this PR).
…contract
- P2-1: InputGroupInput/Textarea spread props before unstyled and
data-maka-field-chrome so a caller's unstyled={false} cannot re-enable
the inner chrome (would double the border / focus ring). The InputGroup
owns the chrome; the inner control stays bare.
- P2-2: port type="search" WebKit cancel/decoration/results reset into
primitives/input. Main's primitives/input always applied this for
InputGroupInput (search-modal path); the unified Input keeps the
contract for both the @maka/ui Input and InputGroupInput paths.
size/nativeInput/type=file variants audited — no callers in repo
(@maka/ui Input was ui.tsx without these; InputGroupInput never
passed them); removed without a compat layer.
- P3-1: rewrite input-canonical-contract as behavior tests only — no
source regex. Styled/unstyled single element + chrome, InputGroup
force-bare even with unstyled={false}, type="search" webkit reset,
barrel import smoke.
- P3-2: #22 PR10 -> #520 item 22 in comments (the PR流水号 narrative
pointed at the wrong tracker).
The canonical Input/Textarea already force data-maka-field-chrome="none"
when unstyled (the {...props} spread precedes the attribute in both
primitives, so a caller cannot override it). The adapter passing it
explicitly was a no-op. Drop the redundant attribute; keep unstyled.
@Astro-HanAstro-Han changed the title feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#22 PR10)feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#520 item 22)Jul 6, 2026
@Astro-Han
Astro-Han merged commit face525 into mainJul 6, 2026
@Astro-Han
Astro-Han deleted the feat/22-input-canonical branch July 6, 2026 05:37
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#520 item 22) by Astro-Han · Pull Request #555 · apache/maka · GitHub
Skip to content

feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#520 item 22) - #555

Merged
Astro-Han merged 3 commits into
mainfrom
feat/22-input-canonical
Jul 6, 2026
Merged

feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#520 item 22)#555
Astro-Han merged 3 commits into
mainfrom
feat/22-input-canonical

Conversation

@Astro-Han

Copy link
Copy Markdown
Contributor

Summary

#22 PR10: collapse the dual Input tracks onto one canonical primitives/input.tsx + primitives/textarea.tsx, retiring the native ui.tsxInput/Textarea.

Why

Refs #22 / #520. The renderer had two parallel Input implementations: the native ui.tsxInput (single <input> + inputClasses, focus-visible:ring-2, used by 44 call sites across 9 settings files) and the Base UI primitives/input.tsxInput (span data-slot="input-control" wrapper + inner Base UI Input + ring-[3px], used by InputGroup). bare-field-chrome-contract pinned the native's data-maka-field-chrome + border-input + ring-2, so retiring the native was not a clean look-preserving swap — it needed inputClasses ported into the Base UI primitive, InputGroup updated to avoid double chrome, and the chrome contract rewritten.

Scope

Changed:

  • primitives/input.tsx now wraps Base UI's Input primitive with maka's inputClasses styling ported as the default chrome. Stays a single <input> (no span wrapper) so caller CSS targeting > input / input:focus-visible still matches. unstyled gives the bare form (bareFieldClasses + data-maka-field-chrome="none") for Field/InputGroup embedding.
  • primitives/textarea.tsx parallel shape: single <textarea> + inputClasses + textarea sizing. Base UI ships no Textarea, so this is a native textarea. Drops the Base UI Field.Control + span wrapper (callers don't use Field).
  • ui.tsxInput, Textarea, inputClasses, bareFieldClasses retired. inputClasses + bareFieldClasses moved into primitives/input.tsx (exported) so number-field keeps its standalone NumberFieldInput chrome.
  • InputGroup: InputGroupInput/InputGroupTextarea already pass unstyled (inner field bare, InputGroup owns the chrome — no double chrome). InputGroup CSS updated to key off data-slot="input"/"textarea" (the single element) instead of the retired span data-slot="input-control"/"textarea-control"; dropped the span-only :contents / :before:hidden rules.
  • index.ts re-exports primitives/input + primitives/textarea as the canonical Input/Textarea; the 44 settings usages keep importing from @maka/ui unchanged.
  • Internal packages/ui imports (composer, plan-reminder-panel, skills-panel) + stories repointed at the primitives.
  • Contracts: new input-canonical-contract (single element, inputClasses token lock, ui.tsx retired, bare-field shape); field-chrome.test rewritten for the unified shape (drops nativeInput/h-8.5/field-sizing-content assertions that pinned the old primitives/input vs ui.tsx divergence); radius-convergeinputClasses tier repointed at primitives/input.tsx.

Not included:

  • PR8 combobox migration (SearchModal + CommandPalette) — separate PR, runtime keyboard interaction risk.

Verification

User-facing impact

None intended. Input/Textarea visuals are preserved by porting inputClasses (min-h-9, border-input, bg-foreground oklch 0.02, px-3 py-2, shadow-sm, focus-visible:ring-2 ring-offset-2) into the Base UI primitive. The DOM changes from a single <input> (ui.tsx) to a single Base UI <input> — still a single <input>, so caller CSS targeting > input keeps matching.

Reviewer notes

  • The single-<input> decision is load-bearing: maka CSS has .settingsRow > input / .settingsField input:focus-visible / .providerEditor input:focus selectors. A span wrapper (the old primitives/input shape) would break the > input direct-child selectors. So the Base UI Input primitive is used directly with inputClasses on it, no span.
  • inputClasses + bareFieldClasses are exported from primitives/input.tsx (not a shared util) because they are the canonical field chrome and number-field is the second consumer of inputClasses for its standalone NumberFieldInput.
  • Textarea drops the Base UI Field.Control wrapper because no caller uses Base UI Field with it; it's a plain native <textarea> with inputClasses. Base UI ships no Textarea component.
  • Commits are independent revert targets; squash on merge.

Checklist

  • Scope matches the PR title and excludes unrelated changes
  • Verification lists commands/results, or explains why they were not run
  • User-facing impact, docs, changelog, migrations, and breaking changes are noted, or marked none
  • Risk, rollback, or review focus is called out for non-trivial changes
  • UI changes include screenshots/video, or explain why not applicable

… Input (#22 PR10)
#22 PR10: collapse the dual Input tracks onto one canonical
primitives/input.tsx + primitives/textarea.tsx, retiring the native ui.tsx
Input/Textarea.
- primitives/input.tsx now wraps Base UI's Input primitive with maka's
inputClasses styling ported as the default chrome. Stays a single <input>
(no span wrapper) so caller CSS targeting `> input` / `input:focus-visible`
still matches. unstyled gives the bare form (bareFieldClasses +
data-maka-field-chrome="none") for Field/InputGroup embedding.
- primitives/textarea.tsx parallel shape: single <textarea> + inputClasses +
textarea sizing. Base UI ships no Textarea, so this is a native textarea.
Drops the Base UI Field.Control + span wrapper (caller doesn't use Field).
- ui.tsx Input, Textarea, inputClasses, bareFieldClasses retired. inputClasses +
bareFieldClasses moved into primitives/input.tsx (exported) so number-field
keeps its standalone NumberFieldInput chrome.
- InputGroup: InputGroupInput/InputGroupTextarea already pass unstyled (inner
field bare, InputGroup owns the chrome — no double chrome). InputGroup CSS
updated to key off data-slot="input"/"textarea" (the single element) instead
of the retired span data-slot="input-control"/"textarea-control"; dropped the
span-only `:contents` / `:before:hidden` rules.
- index.ts re-exports primitives/input + primitives/textarea as the canonical
Input/Textarea; the 44 usages across 9 settings files keep importing from
@maka/ui unchanged.
- Contracts: new input-canonical-contract (single element, inputClasses token
lock, ui.tsx retired, bare-field shape); field-chrome.test rewritten for the
unified shape (drops nativeInput/h-8.5/field-sizing-content assertions that
pinned the old primitives/input vs ui.tsx divergence); radius-converge
inputClasses tier repointed at primitives/input.tsx.
Verification: typecheck clean; @maka/ui test 43/43; @maka/desktop test
2069/2069. Screenshot pixel diff vs main: settings-general and settings-bots
light/dark 1280 AE=0 (pixel-identical, both contain Input). settings-data
364 px (edge); settings-appearance/daily-review ~9-10K px in a 12px right-edge
column (window edge, not input/textarea); settings-memory ~18K px in a large
content block (main-branch composer/sidebar commits #510/#511, not this PR).
…contract
- P2-1: InputGroupInput/Textarea spread props before unstyled and
data-maka-field-chrome so a caller's unstyled={false} cannot re-enable
the inner chrome (would double the border / focus ring). The InputGroup
owns the chrome; the inner control stays bare.
- P2-2: port type="search" WebKit cancel/decoration/results reset into
primitives/input. Main's primitives/input always applied this for
InputGroupInput (search-modal path); the unified Input keeps the
contract for both the @maka/ui Input and InputGroupInput paths.
size/nativeInput/type=file variants audited — no callers in repo
(@maka/ui Input was ui.tsx without these; InputGroupInput never
passed them); removed without a compat layer.
- P3-1: rewrite input-canonical-contract as behavior tests only — no
source regex. Styled/unstyled single element + chrome, InputGroup
force-bare even with unstyled={false}, type="search" webkit reset,
barrel import smoke.
- P3-2: #22 PR10 -> #520 item 22 in comments (the PR流水号 narrative
pointed at the wrong tracker).
The canonical Input/Textarea already force data-maka-field-chrome="none"
when unstyled (the {...props} spread precedes the attribute in both
primitives, so a caller cannot override it). The adapter passing it
explicitly was a no-op. Drop the redundant attribute; keep unstyled.
@Astro-HanAstro-Han changed the title feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#22 PR10)feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#520 item 22)Jul 6, 2026
@Astro-Han
Astro-Han merged commit face525 into mainJul 6, 2026
@Astro-Han
Astro-Han deleted the feat/22-input-canonical branch July 6, 2026 05:37
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#520 item 22) by Astro-Han · Pull Request #555 · apache/maka · GitHub
Skip to content

feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#520 item 22) - #555

Merged
Astro-Han merged 3 commits into
mainfrom
feat/22-input-canonical
Jul 6, 2026
Merged

feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#520 item 22)#555
Astro-Han merged 3 commits into
mainfrom
feat/22-input-canonical

Conversation

@Astro-Han

Copy link
Copy Markdown
Contributor

Summary

#22 PR10: collapse the dual Input tracks onto one canonical primitives/input.tsx + primitives/textarea.tsx, retiring the native ui.tsxInput/Textarea.

Why

Refs #22 / #520. The renderer had two parallel Input implementations: the native ui.tsxInput (single <input> + inputClasses, focus-visible:ring-2, used by 44 call sites across 9 settings files) and the Base UI primitives/input.tsxInput (span data-slot="input-control" wrapper + inner Base UI Input + ring-[3px], used by InputGroup). bare-field-chrome-contract pinned the native's data-maka-field-chrome + border-input + ring-2, so retiring the native was not a clean look-preserving swap — it needed inputClasses ported into the Base UI primitive, InputGroup updated to avoid double chrome, and the chrome contract rewritten.

Scope

Changed:

  • primitives/input.tsx now wraps Base UI's Input primitive with maka's inputClasses styling ported as the default chrome. Stays a single <input> (no span wrapper) so caller CSS targeting > input / input:focus-visible still matches. unstyled gives the bare form (bareFieldClasses + data-maka-field-chrome="none") for Field/InputGroup embedding.
  • primitives/textarea.tsx parallel shape: single <textarea> + inputClasses + textarea sizing. Base UI ships no Textarea, so this is a native textarea. Drops the Base UI Field.Control + span wrapper (callers don't use Field).
  • ui.tsxInput, Textarea, inputClasses, bareFieldClasses retired. inputClasses + bareFieldClasses moved into primitives/input.tsx (exported) so number-field keeps its standalone NumberFieldInput chrome.
  • InputGroup: InputGroupInput/InputGroupTextarea already pass unstyled (inner field bare, InputGroup owns the chrome — no double chrome). InputGroup CSS updated to key off data-slot="input"/"textarea" (the single element) instead of the retired span data-slot="input-control"/"textarea-control"; dropped the span-only :contents / :before:hidden rules.
  • index.ts re-exports primitives/input + primitives/textarea as the canonical Input/Textarea; the 44 settings usages keep importing from @maka/ui unchanged.
  • Internal packages/ui imports (composer, plan-reminder-panel, skills-panel) + stories repointed at the primitives.
  • Contracts: new input-canonical-contract (single element, inputClasses token lock, ui.tsx retired, bare-field shape); field-chrome.test rewritten for the unified shape (drops nativeInput/h-8.5/field-sizing-content assertions that pinned the old primitives/input vs ui.tsx divergence); radius-convergeinputClasses tier repointed at primitives/input.tsx.

Not included:

  • PR8 combobox migration (SearchModal + CommandPalette) — separate PR, runtime keyboard interaction risk.

Verification

User-facing impact

None intended. Input/Textarea visuals are preserved by porting inputClasses (min-h-9, border-input, bg-foreground oklch 0.02, px-3 py-2, shadow-sm, focus-visible:ring-2 ring-offset-2) into the Base UI primitive. The DOM changes from a single <input> (ui.tsx) to a single Base UI <input> — still a single <input>, so caller CSS targeting > input keeps matching.

Reviewer notes

  • The single-<input> decision is load-bearing: maka CSS has .settingsRow > input / .settingsField input:focus-visible / .providerEditor input:focus selectors. A span wrapper (the old primitives/input shape) would break the > input direct-child selectors. So the Base UI Input primitive is used directly with inputClasses on it, no span.
  • inputClasses + bareFieldClasses are exported from primitives/input.tsx (not a shared util) because they are the canonical field chrome and number-field is the second consumer of inputClasses for its standalone NumberFieldInput.
  • Textarea drops the Base UI Field.Control wrapper because no caller uses Base UI Field with it; it's a plain native <textarea> with inputClasses. Base UI ships no Textarea component.
  • Commits are independent revert targets; squash on merge.

Checklist

  • Scope matches the PR title and excludes unrelated changes
  • Verification lists commands/results, or explains why they were not run
  • User-facing impact, docs, changelog, migrations, and breaking changes are noted, or marked none
  • Risk, rollback, or review focus is called out for non-trivial changes
  • UI changes include screenshots/video, or explain why not applicable

… Input (#22 PR10)
#22 PR10: collapse the dual Input tracks onto one canonical
primitives/input.tsx + primitives/textarea.tsx, retiring the native ui.tsx
Input/Textarea.
- primitives/input.tsx now wraps Base UI's Input primitive with maka's
inputClasses styling ported as the default chrome. Stays a single <input>
(no span wrapper) so caller CSS targeting `> input` / `input:focus-visible`
still matches. unstyled gives the bare form (bareFieldClasses +
data-maka-field-chrome="none") for Field/InputGroup embedding.
- primitives/textarea.tsx parallel shape: single <textarea> + inputClasses +
textarea sizing. Base UI ships no Textarea, so this is a native textarea.
Drops the Base UI Field.Control + span wrapper (caller doesn't use Field).
- ui.tsx Input, Textarea, inputClasses, bareFieldClasses retired. inputClasses +
bareFieldClasses moved into primitives/input.tsx (exported) so number-field
keeps its standalone NumberFieldInput chrome.
- InputGroup: InputGroupInput/InputGroupTextarea already pass unstyled (inner
field bare, InputGroup owns the chrome — no double chrome). InputGroup CSS
updated to key off data-slot="input"/"textarea" (the single element) instead
of the retired span data-slot="input-control"/"textarea-control"; dropped the
span-only `:contents` / `:before:hidden` rules.
- index.ts re-exports primitives/input + primitives/textarea as the canonical
Input/Textarea; the 44 usages across 9 settings files keep importing from
@maka/ui unchanged.
- Contracts: new input-canonical-contract (single element, inputClasses token
lock, ui.tsx retired, bare-field shape); field-chrome.test rewritten for the
unified shape (drops nativeInput/h-8.5/field-sizing-content assertions that
pinned the old primitives/input vs ui.tsx divergence); radius-converge
inputClasses tier repointed at primitives/input.tsx.
Verification: typecheck clean; @maka/ui test 43/43; @maka/desktop test
2069/2069. Screenshot pixel diff vs main: settings-general and settings-bots
light/dark 1280 AE=0 (pixel-identical, both contain Input). settings-data
364 px (edge); settings-appearance/daily-review ~9-10K px in a 12px right-edge
column (window edge, not input/textarea); settings-memory ~18K px in a large
content block (main-branch composer/sidebar commits #510/#511, not this PR).
…contract
- P2-1: InputGroupInput/Textarea spread props before unstyled and
data-maka-field-chrome so a caller's unstyled={false} cannot re-enable
the inner chrome (would double the border / focus ring). The InputGroup
owns the chrome; the inner control stays bare.
- P2-2: port type="search" WebKit cancel/decoration/results reset into
primitives/input. Main's primitives/input always applied this for
InputGroupInput (search-modal path); the unified Input keeps the
contract for both the @maka/ui Input and InputGroupInput paths.
size/nativeInput/type=file variants audited — no callers in repo
(@maka/ui Input was ui.tsx without these; InputGroupInput never
passed them); removed without a compat layer.
- P3-1: rewrite input-canonical-contract as behavior tests only — no
source regex. Styled/unstyled single element + chrome, InputGroup
force-bare even with unstyled={false}, type="search" webkit reset,
barrel import smoke.
- P3-2: #22 PR10 -> #520 item 22 in comments (the PR流水号 narrative
pointed at the wrong tracker).
The canonical Input/Textarea already force data-maka-field-chrome="none"
when unstyled (the {...props} spread precedes the attribute in both
primitives, so a caller cannot override it). The adapter passing it
explicitly was a no-op. Drop the redundant attribute; keep unstyled.
@Astro-HanAstro-Han changed the title feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#22 PR10)feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#520 item 22)Jul 6, 2026
@Astro-Han
Astro-Han merged commit face525 into mainJul 6, 2026
@Astro-Han
Astro-Han deleted the feat/22-input-canonical branch July 6, 2026 05:37
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#520 item 22) by Astro-Han · Pull Request #555 · apache/maka · GitHub
Skip to content

feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#520 item 22) - #555

Merged
Astro-Han merged 3 commits into
mainfrom
feat/22-input-canonical
Jul 6, 2026
Merged

feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#520 item 22)#555
Astro-Han merged 3 commits into
mainfrom
feat/22-input-canonical

Conversation

@Astro-Han

Copy link
Copy Markdown
Contributor

Summary

#22 PR10: collapse the dual Input tracks onto one canonical primitives/input.tsx + primitives/textarea.tsx, retiring the native ui.tsxInput/Textarea.

Why

Refs #22 / #520. The renderer had two parallel Input implementations: the native ui.tsxInput (single <input> + inputClasses, focus-visible:ring-2, used by 44 call sites across 9 settings files) and the Base UI primitives/input.tsxInput (span data-slot="input-control" wrapper + inner Base UI Input + ring-[3px], used by InputGroup). bare-field-chrome-contract pinned the native's data-maka-field-chrome + border-input + ring-2, so retiring the native was not a clean look-preserving swap — it needed inputClasses ported into the Base UI primitive, InputGroup updated to avoid double chrome, and the chrome contract rewritten.

Scope

Changed:

  • primitives/input.tsx now wraps Base UI's Input primitive with maka's inputClasses styling ported as the default chrome. Stays a single <input> (no span wrapper) so caller CSS targeting > input / input:focus-visible still matches. unstyled gives the bare form (bareFieldClasses + data-maka-field-chrome="none") for Field/InputGroup embedding.
  • primitives/textarea.tsx parallel shape: single <textarea> + inputClasses + textarea sizing. Base UI ships no Textarea, so this is a native textarea. Drops the Base UI Field.Control + span wrapper (callers don't use Field).
  • ui.tsxInput, Textarea, inputClasses, bareFieldClasses retired. inputClasses + bareFieldClasses moved into primitives/input.tsx (exported) so number-field keeps its standalone NumberFieldInput chrome.
  • InputGroup: InputGroupInput/InputGroupTextarea already pass unstyled (inner field bare, InputGroup owns the chrome — no double chrome). InputGroup CSS updated to key off data-slot="input"/"textarea" (the single element) instead of the retired span data-slot="input-control"/"textarea-control"; dropped the span-only :contents / :before:hidden rules.
  • index.ts re-exports primitives/input + primitives/textarea as the canonical Input/Textarea; the 44 settings usages keep importing from @maka/ui unchanged.
  • Internal packages/ui imports (composer, plan-reminder-panel, skills-panel) + stories repointed at the primitives.
  • Contracts: new input-canonical-contract (single element, inputClasses token lock, ui.tsx retired, bare-field shape); field-chrome.test rewritten for the unified shape (drops nativeInput/h-8.5/field-sizing-content assertions that pinned the old primitives/input vs ui.tsx divergence); radius-convergeinputClasses tier repointed at primitives/input.tsx.

Not included:

  • PR8 combobox migration (SearchModal + CommandPalette) — separate PR, runtime keyboard interaction risk.

Verification

User-facing impact

None intended. Input/Textarea visuals are preserved by porting inputClasses (min-h-9, border-input, bg-foreground oklch 0.02, px-3 py-2, shadow-sm, focus-visible:ring-2 ring-offset-2) into the Base UI primitive. The DOM changes from a single <input> (ui.tsx) to a single Base UI <input> — still a single <input>, so caller CSS targeting > input keeps matching.

Reviewer notes

  • The single-<input> decision is load-bearing: maka CSS has .settingsRow > input / .settingsField input:focus-visible / .providerEditor input:focus selectors. A span wrapper (the old primitives/input shape) would break the > input direct-child selectors. So the Base UI Input primitive is used directly with inputClasses on it, no span.
  • inputClasses + bareFieldClasses are exported from primitives/input.tsx (not a shared util) because they are the canonical field chrome and number-field is the second consumer of inputClasses for its standalone NumberFieldInput.
  • Textarea drops the Base UI Field.Control wrapper because no caller uses Base UI Field with it; it's a plain native <textarea> with inputClasses. Base UI ships no Textarea component.
  • Commits are independent revert targets; squash on merge.

Checklist

  • Scope matches the PR title and excludes unrelated changes
  • Verification lists commands/results, or explains why they were not run
  • User-facing impact, docs, changelog, migrations, and breaking changes are noted, or marked none
  • Risk, rollback, or review focus is called out for non-trivial changes
  • UI changes include screenshots/video, or explain why not applicable

… Input (#22 PR10)
#22 PR10: collapse the dual Input tracks onto one canonical
primitives/input.tsx + primitives/textarea.tsx, retiring the native ui.tsx
Input/Textarea.
- primitives/input.tsx now wraps Base UI's Input primitive with maka's
inputClasses styling ported as the default chrome. Stays a single <input>
(no span wrapper) so caller CSS targeting `> input` / `input:focus-visible`
still matches. unstyled gives the bare form (bareFieldClasses +
data-maka-field-chrome="none") for Field/InputGroup embedding.
- primitives/textarea.tsx parallel shape: single <textarea> + inputClasses +
textarea sizing. Base UI ships no Textarea, so this is a native textarea.
Drops the Base UI Field.Control + span wrapper (caller doesn't use Field).
- ui.tsx Input, Textarea, inputClasses, bareFieldClasses retired. inputClasses +
bareFieldClasses moved into primitives/input.tsx (exported) so number-field
keeps its standalone NumberFieldInput chrome.
- InputGroup: InputGroupInput/InputGroupTextarea already pass unstyled (inner
field bare, InputGroup owns the chrome — no double chrome). InputGroup CSS
updated to key off data-slot="input"/"textarea" (the single element) instead
of the retired span data-slot="input-control"/"textarea-control"; dropped the
span-only `:contents` / `:before:hidden` rules.
- index.ts re-exports primitives/input + primitives/textarea as the canonical
Input/Textarea; the 44 usages across 9 settings files keep importing from
@maka/ui unchanged.
- Contracts: new input-canonical-contract (single element, inputClasses token
lock, ui.tsx retired, bare-field shape); field-chrome.test rewritten for the
unified shape (drops nativeInput/h-8.5/field-sizing-content assertions that
pinned the old primitives/input vs ui.tsx divergence); radius-converge
inputClasses tier repointed at primitives/input.tsx.
Verification: typecheck clean; @maka/ui test 43/43; @maka/desktop test
2069/2069. Screenshot pixel diff vs main: settings-general and settings-bots
light/dark 1280 AE=0 (pixel-identical, both contain Input). settings-data
364 px (edge); settings-appearance/daily-review ~9-10K px in a 12px right-edge
column (window edge, not input/textarea); settings-memory ~18K px in a large
content block (main-branch composer/sidebar commits #510/#511, not this PR).
…contract
- P2-1: InputGroupInput/Textarea spread props before unstyled and
data-maka-field-chrome so a caller's unstyled={false} cannot re-enable
the inner chrome (would double the border / focus ring). The InputGroup
owns the chrome; the inner control stays bare.
- P2-2: port type="search" WebKit cancel/decoration/results reset into
primitives/input. Main's primitives/input always applied this for
InputGroupInput (search-modal path); the unified Input keeps the
contract for both the @maka/ui Input and InputGroupInput paths.
size/nativeInput/type=file variants audited — no callers in repo
(@maka/ui Input was ui.tsx without these; InputGroupInput never
passed them); removed without a compat layer.
- P3-1: rewrite input-canonical-contract as behavior tests only — no
source regex. Styled/unstyled single element + chrome, InputGroup
force-bare even with unstyled={false}, type="search" webkit reset,
barrel import smoke.
- P3-2: #22 PR10 -> #520 item 22 in comments (the PR流水号 narrative
pointed at the wrong tracker).
The canonical Input/Textarea already force data-maka-field-chrome="none"
when unstyled (the {...props} spread precedes the attribute in both
primitives, so a caller cannot override it). The adapter passing it
explicitly was a no-op. Drop the redundant attribute; keep unstyled.
@Astro-HanAstro-Han changed the title feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#22 PR10)feat(ui): canonical Input/Textarea onto Base UI, retire native ui.tsx Input (#520 item 22)Jul 6, 2026
@Astro-Han
Astro-Han merged commit face525 into mainJul 6, 2026
@Astro-Han
Astro-Han deleted the feat/22-input-canonical branch July 6, 2026 05:37
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@Astro-Han