Build TextArea component + fix locale propagation bug across soma providers
Major work in this session:
1. NumberField demo refactored to expose Intl.NumberFormatOptions live
- 9 canonical presets (currency/unit/percent/compact/plain)
- Locale/currency/unit lists derived from $libs/langs, $libs/currency,
$format/units (no more hardcoded arrays)
- Default locale from uix.format.numbers.getLocale()
2. Bug fix: locale prop ignored when soma.format service is active
- soma/NumberField: 5 bypass points via new `hasOwnLocale` getter
(decimalSeparator, groupSeparator, formatValue, formatEditValue, parseValue)
- soma/Calendar: dateOrder respects locale prop (matches DateField precedence)
- soma/RangeCalendar: same dateOrder fix
- When the consumer passes `locale` prop, soma.nums/dates is bypassed
and Intl is used directly with the prop locale
3. TextArea — new component, full 4-layer stack
- morfo: 3 parts (provider/input/count), 3 events
(commit-input/commit-submit/shift-count-overflow), APG textbox
- soma: TextAreaProvider with autosize (scrollHeight measurement),
submitOn modes (false|enter|shift+enter|mod+enter), maxLength soft clamp,
Field integration (OR-merge), counter overflow tracking
- eidos: 5 sizes × 3 variants × 8 colors, autosize suppresses CSS resize
- sema: commit-submit + shift-count-overflow perceptual cues
- demo: canonical 6-tab depth, all props exposed as live controls
- PrimitiveTextareaAttributes added to soma/types/html.ts
4. Also includes accumulated unreleased work from prior sessions:
- Eidos ports: announce, clipboard, drag-drop, feed, table,
tree-grid, tree-view, virtual-grid, virtual-list, words
- Their canonical demos under web/routes/uix/components/
- Semantic events defined for utility morfos
(announce/clipboard/virtual-list/virtual-grid)
- Tree indent guides fixed (TreeView ::before, TreeGrid stacked gradients)
- Sidebar reorganized with Data + Utilities groups
- Eidos words content layer and primitives
Reference library survey performed before TextArea API design (Mantine,
Radix Themes, Chakra v3, React Aria, Ark UI, Bits UI, shadcn, MUI, Prime).
Decision documented: no separate CurrencyField/UnitField — single
NumberField with formatOptions is the canon (matches all surveyed
headless libs except PrimeReact's mode enum, which still uses 1 component).
svelte-check: 0 errors in modified/created files.
See CONTINUE.md for full session notes and next steps.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
|
|
|
[data-words] {
|
|
|
|
|
--_words-gap: var(--words-gap-md);
|
|
|
|
|
--_words-radius: var(--words-radius-md);
|
|
|
|
|
--_words-content-px: var(--words-content-px-md);
|
|
|
|
|
--_words-content-py: var(--words-content-py-md);
|
|
|
|
|
--_words-content-min-block-size: var(--words-content-min-block-size-md);
|
|
|
|
|
--_words-toolbar-px: var(--words-toolbar-px-md);
|
|
|
|
|
--_words-toolbar-py: var(--words-toolbar-py-md);
|
|
|
|
|
--_words-button-size: var(--words-button-size-md);
|
|
|
|
|
--_words-font-size: var(--words-font-size-md);
|
|
|
|
|
--_words-accent-solid: var(--words-color-primary-solid);
|
|
|
|
|
--_words-accent-solid-hover: var(--words-color-primary-solid-hover);
|
|
|
|
|
--_words-accent-track: var(--words-color-primary-track);
|
|
|
|
|
--_words-accent-border: var(--words-color-primary-border);
|
|
|
|
|
--_words-accent-text: var(--words-color-primary-text);
|
|
|
|
|
|
|
|
|
|
position: relative;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
inline-size: 100%;
|
|
|
|
|
max-inline-size: var(--words-max-inline-size);
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
border: var(--words-border-width) solid var(--words-border);
|
|
|
|
|
border-radius: var(--_words-radius);
|
|
|
|
|
background: var(--words-bg);
|
|
|
|
|
box-shadow: var(--words-shadow);
|
|
|
|
|
color: var(--words-color);
|
|
|
|
|
font-family: var(--words-font-family);
|
|
|
|
|
font-size: var(--_words-font-size);
|
|
|
|
|
line-height: var(--words-line-height);
|
|
|
|
|
transition:
|
|
|
|
|
border-color var(--words-transition-duration) var(--words-transition-ease),
|
|
|
|
|
box-shadow var(--words-transition-duration) var(--words-transition-ease),
|
|
|
|
|
background var(--words-transition-duration) var(--words-transition-ease);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words][data-size='sm'] {
|
|
|
|
|
--_words-gap: var(--words-gap-sm);
|
|
|
|
|
--_words-radius: var(--words-radius-sm);
|
|
|
|
|
--_words-content-px: var(--words-content-px-sm);
|
|
|
|
|
--_words-content-py: var(--words-content-py-sm);
|
|
|
|
|
--_words-content-min-block-size: var(--words-content-min-block-size-sm);
|
|
|
|
|
--_words-toolbar-px: var(--words-toolbar-px-sm);
|
|
|
|
|
--_words-toolbar-py: var(--words-toolbar-py-sm);
|
|
|
|
|
--_words-button-size: var(--words-button-size-sm);
|
|
|
|
|
--_words-font-size: var(--words-font-size-sm);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words][data-size='lg'] {
|
|
|
|
|
--_words-gap: var(--words-gap-lg);
|
|
|
|
|
--_words-radius: var(--words-radius-lg);
|
|
|
|
|
--_words-content-px: var(--words-content-px-lg);
|
|
|
|
|
--_words-content-py: var(--words-content-py-lg);
|
|
|
|
|
--_words-content-min-block-size: var(--words-content-min-block-size-lg);
|
|
|
|
|
--_words-toolbar-px: var(--words-toolbar-px-lg);
|
|
|
|
|
--_words-toolbar-py: var(--words-toolbar-py-lg);
|
|
|
|
|
--_words-button-size: var(--words-button-size-lg);
|
|
|
|
|
--_words-font-size: var(--words-font-size-lg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words][data-color='secondary'] {
|
|
|
|
|
--_words-accent-solid: var(--words-color-secondary-solid);
|
|
|
|
|
--_words-accent-solid-hover: var(--words-color-secondary-solid-hover);
|
|
|
|
|
--_words-accent-track: var(--words-color-secondary-track);
|
|
|
|
|
--_words-accent-border: var(--words-color-secondary-border);
|
|
|
|
|
--_words-accent-text: var(--words-color-secondary-text);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words][data-color='neutral'] {
|
|
|
|
|
--_words-accent-solid: var(--words-color-neutral-solid);
|
|
|
|
|
--_words-accent-solid-hover: var(--words-color-neutral-solid-hover);
|
|
|
|
|
--_words-accent-track: var(--words-color-neutral-track);
|
|
|
|
|
--_words-accent-border: var(--words-color-neutral-border);
|
|
|
|
|
--_words-accent-text: var(--words-color-neutral-text);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words][data-color='affirm'] {
|
|
|
|
|
--_words-accent-solid: var(--words-color-affirm-solid);
|
|
|
|
|
--_words-accent-solid-hover: var(--words-color-affirm-solid-hover);
|
|
|
|
|
--_words-accent-track: var(--words-color-affirm-track);
|
|
|
|
|
--_words-accent-border: var(--words-color-affirm-border);
|
|
|
|
|
--_words-accent-text: var(--words-color-affirm-text);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words][data-color='fulfill'] {
|
|
|
|
|
--_words-accent-solid: var(--words-color-fulfill-solid);
|
|
|
|
|
--_words-accent-solid-hover: var(--words-color-fulfill-solid-hover);
|
|
|
|
|
--_words-accent-track: var(--words-color-fulfill-track);
|
|
|
|
|
--_words-accent-border: var(--words-color-fulfill-border);
|
|
|
|
|
--_words-accent-text: var(--words-color-fulfill-text);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words][data-color='risk'] {
|
|
|
|
|
--_words-accent-solid: var(--words-color-risk-solid);
|
|
|
|
|
--_words-accent-solid-hover: var(--words-color-risk-solid-hover);
|
|
|
|
|
--_words-accent-track: var(--words-color-risk-track);
|
|
|
|
|
--_words-accent-border: var(--words-color-risk-border);
|
|
|
|
|
--_words-accent-text: var(--words-color-risk-text);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words][data-color='threat'] {
|
|
|
|
|
--_words-accent-solid: var(--words-color-threat-solid);
|
|
|
|
|
--_words-accent-solid-hover: var(--words-color-threat-solid-hover);
|
|
|
|
|
--_words-accent-track: var(--words-color-threat-track);
|
|
|
|
|
--_words-accent-border: var(--words-color-threat-border);
|
|
|
|
|
--_words-accent-text: var(--words-color-threat-text);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words][data-color='loss'] {
|
|
|
|
|
--_words-accent-solid: var(--words-color-loss-solid);
|
|
|
|
|
--_words-accent-solid-hover: var(--words-color-loss-solid-hover);
|
|
|
|
|
--_words-accent-track: var(--words-color-loss-track);
|
|
|
|
|
--_words-accent-border: var(--words-color-loss-border);
|
|
|
|
|
--_words-accent-text: var(--words-color-loss-text);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words][data-variant='outline'] {
|
|
|
|
|
background: transparent;
|
|
|
|
|
box-shadow: none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words][data-variant='ghost'] {
|
|
|
|
|
border-color: transparent;
|
|
|
|
|
background: transparent;
|
|
|
|
|
box-shadow: none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words]:hover:not([data-disabled]):not([data-readonly]) {
|
|
|
|
|
border-color: var(--words-border-hover);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words][data-focused] {
|
|
|
|
|
border-color: var(--_words-accent-border);
|
|
|
|
|
box-shadow: var(--words-focus-shadow);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words][data-invalid] {
|
|
|
|
|
border-color: var(--words-invalid-border);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words][data-disabled] {
|
|
|
|
|
cursor: not-allowed;
|
|
|
|
|
opacity: var(--words-disabled-opacity);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words]:has([data-words-toolbar][data-orientation='vertical']) {
|
|
|
|
|
display: grid;
|
|
|
|
|
grid-template-columns: max-content minmax(0, 1fr);
|
feat: build PasswordField (full stack)
Dedicated password input component — matches the Ark UI / Chakra v3 /
Mantine / PrimeReact / Ant Design pattern of treating PasswordField as
its own first-class component (not a TextField variant). Includes one
feature that NO surveyed library ships: a CapsLock indicator driven by
KeyboardEvent.getModifierState('CapsLock').
Anatomy (5 parts, 4 events):
- Provider (root, value + visibility state)
- Input (the textbox; type flips between password / text)
- VisibilityTrigger (eye toggle button; aria-pressed + aria-controls)
- CapsLockIndicator (status live region; data-active toggles via soma
listening to keydown/keyup on Input)
- StrengthMeter (composable; consumer provides 0-4 score; UIX bundles
no zxcvbn-style algorithm — dependency-free by design)
Events:
- commit-input (every keystroke)
- commit-submit (Enter)
- shift-toggle-visibility (eye click)
- shift-caps-state (Caps Lock state flips while focused)
Key behaviors:
- `purpose: 'current' | 'new'` drives native autocomplete attribute
('current-password' for login / 'new-password' for registration).
- Field integration: disabled/readonly/required/invalid OR-merged.
- VisibilityTrigger gets tabindex=-1 so it doesn't break the form's
natural tab order — mouse / programmatic focus only, matching Ark UI.
- Caps Lock indicator is aria-live="polite" — announces on activation
while focused, silent when inactive.
- Letter-spacing increased on the input for legibility while masked.
Reference library survey performed (10 libraries) before implementation —
all consensus around dedicated component, all have built-in toggle,
ZERO have caps lock warning. Documented in the demo's API tab with a
feature comparison table.
Demo follows DEMO_AUTHORING_GUIDE canonical 6-tab depth: Live (controls
grouped by layer + code snippets at the bottom), API (props + reference
comparison), Morfo (field/value + Parts + Events tables), Sema (events
table with ▶ play), Recipe (selectors with morfo/eidos owner tags), A11y
(concern/contract table).
Also includes external work in words/ from a separate session
(unrelated to PasswordField) — not touching Words is the standing rule,
but the diff was already in the working tree.
svelte-check: 0 errors in PasswordField files (Words errors are tracked
by its own development branch).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
|
|
|
grid-template-rows: auto auto;
|
|
|
|
|
}
|
|
|
|
|
|
Build TextArea component + fix locale propagation bug across soma providers
Major work in this session:
1. NumberField demo refactored to expose Intl.NumberFormatOptions live
- 9 canonical presets (currency/unit/percent/compact/plain)
- Locale/currency/unit lists derived from $libs/langs, $libs/currency,
$format/units (no more hardcoded arrays)
- Default locale from uix.format.numbers.getLocale()
2. Bug fix: locale prop ignored when soma.format service is active
- soma/NumberField: 5 bypass points via new `hasOwnLocale` getter
(decimalSeparator, groupSeparator, formatValue, formatEditValue, parseValue)
- soma/Calendar: dateOrder respects locale prop (matches DateField precedence)
- soma/RangeCalendar: same dateOrder fix
- When the consumer passes `locale` prop, soma.nums/dates is bypassed
and Intl is used directly with the prop locale
3. TextArea — new component, full 4-layer stack
- morfo: 3 parts (provider/input/count), 3 events
(commit-input/commit-submit/shift-count-overflow), APG textbox
- soma: TextAreaProvider with autosize (scrollHeight measurement),
submitOn modes (false|enter|shift+enter|mod+enter), maxLength soft clamp,
Field integration (OR-merge), counter overflow tracking
- eidos: 5 sizes × 3 variants × 8 colors, autosize suppresses CSS resize
- sema: commit-submit + shift-count-overflow perceptual cues
- demo: canonical 6-tab depth, all props exposed as live controls
- PrimitiveTextareaAttributes added to soma/types/html.ts
4. Also includes accumulated unreleased work from prior sessions:
- Eidos ports: announce, clipboard, drag-drop, feed, table,
tree-grid, tree-view, virtual-grid, virtual-list, words
- Their canonical demos under web/routes/uix/components/
- Semantic events defined for utility morfos
(announce/clipboard/virtual-list/virtual-grid)
- Tree indent guides fixed (TreeView ::before, TreeGrid stacked gradients)
- Sidebar reorganized with Data + Utilities groups
- Eidos words content layer and primitives
Reference library survey performed before TextArea API design (Mantine,
Radix Themes, Chakra v3, React Aria, Ark UI, Bits UI, shadcn, MUI, Prime).
Decision documented: no separate CurrencyField/UnitField — single
NumberField with formatOptions is the canon (matches all surveyed
headless libs except PrimeReact's mode enum, which still uses 1 component).
svelte-check: 0 errors in modified/created files.
See CONTINUE.md for full session notes and next steps.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
|
|
|
[data-words-toolbar] {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: var(--words-toolbar-gap);
|
|
|
|
|
padding-block: var(--_words-toolbar-py);
|
|
|
|
|
padding-inline: var(--_words-toolbar-px);
|
|
|
|
|
border-block-end: var(--words-border-width) solid var(--words-toolbar-border);
|
|
|
|
|
background: var(--words-toolbar-bg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words-toolbar][data-orientation='vertical'] {
|
|
|
|
|
grid-column: 1;
|
|
|
|
|
grid-row: 1;
|
Build TextArea component + fix locale propagation bug across soma providers
Major work in this session:
1. NumberField demo refactored to expose Intl.NumberFormatOptions live
- 9 canonical presets (currency/unit/percent/compact/plain)
- Locale/currency/unit lists derived from $libs/langs, $libs/currency,
$format/units (no more hardcoded arrays)
- Default locale from uix.format.numbers.getLocale()
2. Bug fix: locale prop ignored when soma.format service is active
- soma/NumberField: 5 bypass points via new `hasOwnLocale` getter
(decimalSeparator, groupSeparator, formatValue, formatEditValue, parseValue)
- soma/Calendar: dateOrder respects locale prop (matches DateField precedence)
- soma/RangeCalendar: same dateOrder fix
- When the consumer passes `locale` prop, soma.nums/dates is bypassed
and Intl is used directly with the prop locale
3. TextArea — new component, full 4-layer stack
- morfo: 3 parts (provider/input/count), 3 events
(commit-input/commit-submit/shift-count-overflow), APG textbox
- soma: TextAreaProvider with autosize (scrollHeight measurement),
submitOn modes (false|enter|shift+enter|mod+enter), maxLength soft clamp,
Field integration (OR-merge), counter overflow tracking
- eidos: 5 sizes × 3 variants × 8 colors, autosize suppresses CSS resize
- sema: commit-submit + shift-count-overflow perceptual cues
- demo: canonical 6-tab depth, all props exposed as live controls
- PrimitiveTextareaAttributes added to soma/types/html.ts
4. Also includes accumulated unreleased work from prior sessions:
- Eidos ports: announce, clipboard, drag-drop, feed, table,
tree-grid, tree-view, virtual-grid, virtual-list, words
- Their canonical demos under web/routes/uix/components/
- Semantic events defined for utility morfos
(announce/clipboard/virtual-list/virtual-grid)
- Tree indent guides fixed (TreeView ::before, TreeGrid stacked gradients)
- Sidebar reorganized with Data + Utilities groups
- Eidos words content layer and primitives
Reference library survey performed before TextArea API design (Mantine,
Radix Themes, Chakra v3, React Aria, Ark UI, Bits UI, shadcn, MUI, Prime).
Decision documented: no separate CurrencyField/UnitField — single
NumberField with formatOptions is the canon (matches all surveyed
headless libs except PrimeReact's mode enum, which still uses 1 component).
svelte-check: 0 errors in modified/created files.
See CONTINUE.md for full session notes and next steps.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
|
|
|
flex-direction: column;
|
|
|
|
|
align-items: stretch;
|
|
|
|
|
inline-size: max-content;
|
|
|
|
|
border-block-end: 0;
|
|
|
|
|
border-inline-end: var(--words-border-width) solid var(--words-toolbar-border);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words-toolbar-group] {
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: var(--words-command-gap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words-toolbar-group][data-orientation='vertical'] {
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
align-items: stretch;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words-command-button] {
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
gap: var(--words-command-gap);
|
|
|
|
|
min-inline-size: var(--_words-button-size);
|
|
|
|
|
block-size: var(--_words-button-size);
|
|
|
|
|
padding-inline: var(--words-command-px);
|
|
|
|
|
border: var(--words-border-width) solid transparent;
|
|
|
|
|
border-radius: var(--words-command-radius);
|
|
|
|
|
background: transparent;
|
|
|
|
|
color: var(--words-command-color);
|
|
|
|
|
font: inherit;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
outline: none;
|
|
|
|
|
transition:
|
|
|
|
|
background var(--words-transition-duration) var(--words-transition-ease),
|
|
|
|
|
border-color var(--words-transition-duration) var(--words-transition-ease),
|
|
|
|
|
color var(--words-transition-duration) var(--words-transition-ease),
|
|
|
|
|
box-shadow var(--words-transition-duration) var(--words-transition-ease);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words-command-button]:hover:not(:disabled):not([data-disabled]) {
|
|
|
|
|
border-color: var(--words-command-border-hover);
|
|
|
|
|
background: var(--words-command-bg-hover);
|
|
|
|
|
color: var(--words-command-color-hover);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words-command-button]:focus-visible {
|
|
|
|
|
box-shadow: var(--words-focus-shadow);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words-command-button][data-active],
|
|
|
|
|
[data-words-command-button][data-state='on'] {
|
|
|
|
|
border-color: var(--_words-accent-border);
|
|
|
|
|
background: var(--_words-accent-track);
|
|
|
|
|
color: var(--_words-accent-text);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words-command-button][data-command='commit'] {
|
|
|
|
|
border-color: var(--_words-accent-solid);
|
|
|
|
|
background: var(--_words-accent-solid);
|
|
|
|
|
color: var(--words-command-solid-color);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words-command-button][data-command='commit']:hover:not(:disabled):not([data-disabled]) {
|
|
|
|
|
border-color: var(--_words-accent-solid-hover);
|
|
|
|
|
background: var(--_words-accent-solid-hover);
|
|
|
|
|
color: var(--words-command-solid-color);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words-command-button]:disabled,
|
|
|
|
|
[data-words-command-button][data-disabled] {
|
|
|
|
|
cursor: not-allowed;
|
|
|
|
|
opacity: var(--words-disabled-opacity);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words-placeholder] {
|
|
|
|
|
display: block;
|
|
|
|
|
padding-block-start: var(--_words-content-py);
|
|
|
|
|
padding-inline: var(--_words-content-px);
|
|
|
|
|
color: var(--words-placeholder-color);
|
|
|
|
|
pointer-events: none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words]:has([data-words-toolbar][data-orientation='vertical']) [data-words-placeholder] {
|
|
|
|
|
grid-column: 2;
|
|
|
|
|
grid-row: 1;
|
|
|
|
|
z-index: 1;
|
|
|
|
|
}
|
|
|
|
|
|
Build TextArea component + fix locale propagation bug across soma providers
Major work in this session:
1. NumberField demo refactored to expose Intl.NumberFormatOptions live
- 9 canonical presets (currency/unit/percent/compact/plain)
- Locale/currency/unit lists derived from $libs/langs, $libs/currency,
$format/units (no more hardcoded arrays)
- Default locale from uix.format.numbers.getLocale()
2. Bug fix: locale prop ignored when soma.format service is active
- soma/NumberField: 5 bypass points via new `hasOwnLocale` getter
(decimalSeparator, groupSeparator, formatValue, formatEditValue, parseValue)
- soma/Calendar: dateOrder respects locale prop (matches DateField precedence)
- soma/RangeCalendar: same dateOrder fix
- When the consumer passes `locale` prop, soma.nums/dates is bypassed
and Intl is used directly with the prop locale
3. TextArea — new component, full 4-layer stack
- morfo: 3 parts (provider/input/count), 3 events
(commit-input/commit-submit/shift-count-overflow), APG textbox
- soma: TextAreaProvider with autosize (scrollHeight measurement),
submitOn modes (false|enter|shift+enter|mod+enter), maxLength soft clamp,
Field integration (OR-merge), counter overflow tracking
- eidos: 5 sizes × 3 variants × 8 colors, autosize suppresses CSS resize
- sema: commit-submit + shift-count-overflow perceptual cues
- demo: canonical 6-tab depth, all props exposed as live controls
- PrimitiveTextareaAttributes added to soma/types/html.ts
4. Also includes accumulated unreleased work from prior sessions:
- Eidos ports: announce, clipboard, drag-drop, feed, table,
tree-grid, tree-view, virtual-grid, virtual-list, words
- Their canonical demos under web/routes/uix/components/
- Semantic events defined for utility morfos
(announce/clipboard/virtual-list/virtual-grid)
- Tree indent guides fixed (TreeView ::before, TreeGrid stacked gradients)
- Sidebar reorganized with Data + Utilities groups
- Eidos words content layer and primitives
Reference library survey performed before TextArea API design (Mantine,
Radix Themes, Chakra v3, React Aria, Ark UI, Bits UI, shadcn, MUI, Prime).
Decision documented: no separate CurrencyField/UnitField — single
NumberField with formatOptions is the canon (matches all surveyed
headless libs except PrimeReact's mode enum, which still uses 1 component).
svelte-check: 0 errors in modified/created files.
See CONTINUE.md for full session notes and next steps.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
|
|
|
[data-words-placeholder][hidden],
|
|
|
|
|
[data-words-hidden-input][hidden] {
|
|
|
|
|
display: none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words-content] {
|
|
|
|
|
min-block-size: var(--_words-content-min-block-size);
|
|
|
|
|
padding-block: var(--_words-content-py);
|
|
|
|
|
padding-inline: var(--_words-content-px);
|
|
|
|
|
color: var(--words-content-color);
|
|
|
|
|
outline: none;
|
|
|
|
|
overflow-wrap: anywhere;
|
|
|
|
|
caret-color: var(--_words-accent-solid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words]:has([data-words-toolbar][data-orientation='vertical']) [data-words-content] {
|
|
|
|
|
grid-column: 2;
|
|
|
|
|
grid-row: 1;
|
|
|
|
|
}
|
|
|
|
|
|
Build TextArea component + fix locale propagation bug across soma providers
Major work in this session:
1. NumberField demo refactored to expose Intl.NumberFormatOptions live
- 9 canonical presets (currency/unit/percent/compact/plain)
- Locale/currency/unit lists derived from $libs/langs, $libs/currency,
$format/units (no more hardcoded arrays)
- Default locale from uix.format.numbers.getLocale()
2. Bug fix: locale prop ignored when soma.format service is active
- soma/NumberField: 5 bypass points via new `hasOwnLocale` getter
(decimalSeparator, groupSeparator, formatValue, formatEditValue, parseValue)
- soma/Calendar: dateOrder respects locale prop (matches DateField precedence)
- soma/RangeCalendar: same dateOrder fix
- When the consumer passes `locale` prop, soma.nums/dates is bypassed
and Intl is used directly with the prop locale
3. TextArea — new component, full 4-layer stack
- morfo: 3 parts (provider/input/count), 3 events
(commit-input/commit-submit/shift-count-overflow), APG textbox
- soma: TextAreaProvider with autosize (scrollHeight measurement),
submitOn modes (false|enter|shift+enter|mod+enter), maxLength soft clamp,
Field integration (OR-merge), counter overflow tracking
- eidos: 5 sizes × 3 variants × 8 colors, autosize suppresses CSS resize
- sema: commit-submit + shift-count-overflow perceptual cues
- demo: canonical 6-tab depth, all props exposed as live controls
- PrimitiveTextareaAttributes added to soma/types/html.ts
4. Also includes accumulated unreleased work from prior sessions:
- Eidos ports: announce, clipboard, drag-drop, feed, table,
tree-grid, tree-view, virtual-grid, virtual-list, words
- Their canonical demos under web/routes/uix/components/
- Semantic events defined for utility morfos
(announce/clipboard/virtual-list/virtual-grid)
- Tree indent guides fixed (TreeView ::before, TreeGrid stacked gradients)
- Sidebar reorganized with Data + Utilities groups
- Eidos words content layer and primitives
Reference library survey performed before TextArea API design (Mantine,
Radix Themes, Chakra v3, React Aria, Ark UI, Bits UI, shadcn, MUI, Prime).
Decision documented: no separate CurrencyField/UnitField — single
NumberField with formatOptions is the canon (matches all surveyed
headless libs except PrimeReact's mode enum, which still uses 1 component).
svelte-check: 0 errors in modified/created files.
See CONTINUE.md for full session notes and next steps.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
|
|
|
[data-words-placeholder]:not([hidden]) + [data-words-content] {
|
|
|
|
|
padding-block-start: var(--words-content-py-after-placeholder);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words-content]::selection,
|
|
|
|
|
[data-words-content] ::selection {
|
|
|
|
|
background: var(--_words-accent-track);
|
|
|
|
|
color: var(--words-selection-color);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words-content]:focus-visible {
|
|
|
|
|
outline: none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words-content] :where(p, h1, h2, h3, blockquote, ul, ol) {
|
|
|
|
|
margin-block: 0 var(--words-block-gap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words-content] :where(p, h1, h2, h3, blockquote, ul, ol):last-child {
|
|
|
|
|
margin-block-end: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words-content] :where(h1, h2, h3) {
|
|
|
|
|
color: var(--words-heading-color);
|
|
|
|
|
font-size: var(--words-heading-font-size);
|
|
|
|
|
font-weight: var(--words-heading-font-weight);
|
|
|
|
|
line-height: var(--words-heading-line-height);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words-content] :where(strong) {
|
|
|
|
|
font-weight: var(--words-strong-font-weight);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words-content] [data-words-marks~='bold'] {
|
|
|
|
|
font-weight: var(--words-strong-font-weight);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words-content] [data-words-marks~='italic'] {
|
|
|
|
|
font-style: italic;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words-content] [data-words-marks~='underline'] {
|
|
|
|
|
text-decoration-line: underline;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words-content] [data-words-marks~='strike'] {
|
|
|
|
|
text-decoration-line: line-through;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words-content] [data-words-marks~='underline'][data-words-marks~='strike'] {
|
|
|
|
|
text-decoration-line: underline line-through;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words-content] :where(code) {
|
|
|
|
|
border-radius: var(--words-code-radius);
|
|
|
|
|
background: var(--words-code-bg);
|
|
|
|
|
color: var(--words-code-color);
|
|
|
|
|
font-family: var(--words-code-font-family);
|
|
|
|
|
padding-block: var(--words-code-py);
|
|
|
|
|
padding-inline: var(--words-code-px);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words-content] [data-words-marks~='code'] {
|
|
|
|
|
border-radius: var(--words-code-radius);
|
|
|
|
|
background: var(--words-code-bg);
|
|
|
|
|
color: var(--words-code-color);
|
|
|
|
|
font-family: var(--words-code-font-family);
|
|
|
|
|
padding-block: var(--words-code-py);
|
|
|
|
|
padding-inline: var(--words-code-px);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words-content] :where(blockquote) {
|
|
|
|
|
padding-inline-start: var(--words-quote-px);
|
|
|
|
|
border-inline-start: var(--words-quote-border-width) solid var(--_words-accent-border);
|
|
|
|
|
color: var(--words-quote-color);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words-content] :where(ul, ol) {
|
|
|
|
|
padding-inline-start: var(--words-list-padding-inline-start);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words-content] :where(a) {
|
|
|
|
|
color: var(--_words-accent-text);
|
|
|
|
|
text-decoration-color: var(--_words-accent-border);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words-status] {
|
|
|
|
|
padding-block: var(--words-status-py);
|
|
|
|
|
padding-inline: var(--_words-content-px);
|
|
|
|
|
border-block-start: var(--words-border-width) solid var(--words-toolbar-border);
|
|
|
|
|
color: var(--words-status-color);
|
|
|
|
|
font-size: var(--words-status-font-size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-words]:has([data-words-toolbar][data-orientation='vertical']) [data-words-status] {
|
|
|
|
|
grid-column: 1 / -1;
|
|
|
|
|
grid-row: 2;
|
|
|
|
|
}
|
|
|
|
|
|
Build TextArea component + fix locale propagation bug across soma providers
Major work in this session:
1. NumberField demo refactored to expose Intl.NumberFormatOptions live
- 9 canonical presets (currency/unit/percent/compact/plain)
- Locale/currency/unit lists derived from $libs/langs, $libs/currency,
$format/units (no more hardcoded arrays)
- Default locale from uix.format.numbers.getLocale()
2. Bug fix: locale prop ignored when soma.format service is active
- soma/NumberField: 5 bypass points via new `hasOwnLocale` getter
(decimalSeparator, groupSeparator, formatValue, formatEditValue, parseValue)
- soma/Calendar: dateOrder respects locale prop (matches DateField precedence)
- soma/RangeCalendar: same dateOrder fix
- When the consumer passes `locale` prop, soma.nums/dates is bypassed
and Intl is used directly with the prop locale
3. TextArea — new component, full 4-layer stack
- morfo: 3 parts (provider/input/count), 3 events
(commit-input/commit-submit/shift-count-overflow), APG textbox
- soma: TextAreaProvider with autosize (scrollHeight measurement),
submitOn modes (false|enter|shift+enter|mod+enter), maxLength soft clamp,
Field integration (OR-merge), counter overflow tracking
- eidos: 5 sizes × 3 variants × 8 colors, autosize suppresses CSS resize
- sema: commit-submit + shift-count-overflow perceptual cues
- demo: canonical 6-tab depth, all props exposed as live controls
- PrimitiveTextareaAttributes added to soma/types/html.ts
4. Also includes accumulated unreleased work from prior sessions:
- Eidos ports: announce, clipboard, drag-drop, feed, table,
tree-grid, tree-view, virtual-grid, virtual-list, words
- Their canonical demos under web/routes/uix/components/
- Semantic events defined for utility morfos
(announce/clipboard/virtual-list/virtual-grid)
- Tree indent guides fixed (TreeView ::before, TreeGrid stacked gradients)
- Sidebar reorganized with Data + Utilities groups
- Eidos words content layer and primitives
Reference library survey performed before TextArea API design (Mantine,
Radix Themes, Chakra v3, React Aria, Ark UI, Bits UI, shadcn, MUI, Prime).
Decision documented: no separate CurrencyField/UnitField — single
NumberField with formatOptions is the canon (matches all surveyed
headless libs except PrimeReact's mode enum, which still uses 1 component).
svelte-check: 0 errors in modified/created files.
See CONTINUE.md for full session notes and next steps.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
|
|
|
[data-words-status][data-status='error'] {
|
|
|
|
|
color: var(--words-status-error-color);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
|
|
|
[data-words],
|
|
|
|
|
[data-words-command-button] {
|
|
|
|
|
transition: none;
|
|
|
|
|
}
|
|
|
|
|
}
|