diff --git a/STYLE-SYSTEM-COMPLETION-PLAN.md b/STYLE-SYSTEM-COMPLETION-PLAN.md deleted file mode 100644 index 0c20937..0000000 --- a/STYLE-SYSTEM-COMPLETION-PLAN.md +++ /dev/null @@ -1,570 +0,0 @@ -# План завершения стилевой системы Glint - -## Цель - -Достичь полной мощности HTML+CSS в языке Glint. Система разделена на 4 уровня: -- **Парсер** (glt/src/style_parser.rs) — чтение `.glts` -- **AST + Компилятор** (glt/src/ast.rs, compiler.rs) — представление и байткод -- **Интерпретатор** (runtime/src/interpreter/) — VDOM + вычисление стилей -- **Рендерер** (runtime/src/renderer.rs) — отрисовка через Iced - ---- - -## 1. Селекторы (критично) - -### 1.1 Структурированное представление селектора - -**Сейчас:** Селектор — плоская строка `"Panel.desktop"`, matching по точному совпадению. - -**Нужно:** Разобрать селектор в структуру: - -```rust -enum Selector { - Simple(SimpleSelector), - Compound(CompoundSelector), // без комбинатора - Complex { - left: Box, - combinator: Combinator, - right: Box, - }, - List(Vec), // запятые: `Button, .btn, #id` -} - -struct SimpleSelector { - tag: Option, // `Button` | `*` - id: Option, // `#myid` - classes: Vec, // `.foo.bar` - pseudo_classes: Vec, // `:hover` - pseudo_element: Option, // `::before` - attribute: Vec, // `[disabled]`, `[type="text"]` -} - -enum Combinator { - Descendant, // пробел - Child, // > - NextSibling, // + - Subsequent, // ~ -} - -enum PseudoClass { - Hover, Active, Focus, - FirstChild, LastChild, - NthChild(i32, i32), // An+B - FirstOfType, LastOfType, - Disabled, Enabled, Checked, - Root, Empty, - Not(Box), - // ... -} - -struct AttributeSelector { - name: String, - op: AttrOp, - value: Option, -} - -enum AttrOp { Set, Eq, Contain, StartsWith, EndsWith, InList } -``` - -### 1.2 Парсинг селекторов (style_parser.rs) - -- Заменить `parse_selector()` на полноценный парсер селекторов. -- Поддержка: `Button.active:hover`, `Panel > .btn`, `#header`, `[type="text"]`, `*`, `:nth-child(2n+1)`, запятые. -- Валидация и сообщения об ошибках. - -### 1.3 Байткод для селекторов - -- Новый опкод `OP_SELECTOR` или расширение `OP_STYLE_RULE`: - - Записать дерево селектора в байткод. - - На каждый тип узла — свой подопкод (0x30–0x3F). -- Компилятор: сериализация структуры селектора. -- Читатель (reader.rs): десериализация обратно в структуру. - -### 1.4 Runtime matching (interpreter/mod.rs) - -- Заменить `collect_matching_styles()` на алгоритм обхода дерева селекторов. -- **Специфичность:** inline > id > class/attr/pseudo > tag. -- При одинаковой специфичности — порядок объявления (последний побеждает). -- **Комбинаторы:** при обходе VDOM подниматься вверх по предкам/соседям. -- Кэширование результатов matching для производительности. - ---- - -## 2. Псевдоклассы (высокий приоритет) - -### 2.1 Интерактивные (`:hover`, `:active`, `:focus`) - -**Сейчас:** Только у Button ховер/нажатие — хардкод в renderer. - -**Нужно:** -- Хранить состояние интерактивности в VDOM/Element (`ElementState`). -- В renderer передавать статус (hovered/pressed/focused) в `collect_matching_styles`. -- `:hover`-стили переопределяют базовые. -- Плавный переход между состояниями (см. transitions). - -**Изменения:** -- `types.rs`: `Element` может получить поле `state: ElementState`. -- `renderer.rs`: у `render_element` появляется доступ к состоянию мыши. -- `style.rs`: `ComputedStyle::compute()` принимает псевдоклассы. - -### 2.2 Структурные (`:first-child`, `:nth-child`, `:last-child`, `:first-of-type`, `:last-of-type`, `:empty`, `:root`) - -**Сейчас:** Не поддерживаются. - -**Нужно:** -- При matching вычислять позицию элемента среди siblings. -- Для `:nth-child(An+B)` — парсить выражение и проверять `(index - B) % A == 0`. -- `:empty` — `el.children.is_empty()`. -- `:root` — элемент верхнего уровня в VDOM. - -### 2.3 Состояния (`:disabled`, `:enabled`, `:checked`) - -- `:disabled`/`:enabled` — по свойству `disabled`. -- `:checked` — по свойству `checked`. - ---- - -## 3. Медиа-запросы (`@media`) (средний приоритет) - -### 3.1 Парсер - -```glts -@media (max-width: 600px) { - Panel { direction: vertical } -} -``` - -- Парсить `@media` в `Directive::MediaQuery { query, child_span }`. -- Поддержка: `width`, `height`, `min-width`, `max-width`, `orientation`, `prefers-color-scheme`. -- Логические операторы: `and`, `or`, `not`, `,` (or). - -### 3.2 Runtime - -- Собрать информацию об окне (размер, тема ОС). -- При изменении размера окна переоценивать media queries. -- Хранить в `Document::media_state: MediaState`. -- `collect_matching_styles` проверяет media query перед добавлением правил. - ---- - -## 4. Анимации (`@anim`) (средний приоритет) - -### 4.1 Парсинг — уже есть - -`@anim name { from { ... } to { ... } }` — парсится и компилируется. - -### 4.2 Runtime — НЕ реализован - -**Сейчас:** `OP_STYLE_ANIM` пропускается. - -**Нужно:** -1. Хранить `KeyframeAnimation` в `StyleSheet` (не только в байткоде, но и в runtime-структуре). -2. В `Element` поле `animation_state: HashMap`. -3. Система тиков: - - Iced `subscription` на каждый кадр (`on_every_event` → `Event::Window(RedrawRequested)`). - - При каждом тике обновлять `elapsed` для активных анимаций. - - Интерполировать между keyframes. -4. Свойства `animation-name`, `animation-duration`, `animation-timing-function`, `animation-delay`, `animation-iteration-count`, `animation-fill-mode`. -5. Поддержка `@keyframes` с процентами: `0% { ... } 50% { ... } 100% { ... }`. - -### 4.3 Timing functions - -- `linear`, `ease`, `ease-in`, `ease-out`, `ease-in-out`. -- `cubic-bezier(p1x, p1y, p2x, p2y)`. -- `steps(n, direction)`. - ---- - -## 5. Транзишены (`transition`) (средний приоритет) - -### 5.1 Свойства - -- `transition-property`, `transition-duration`, `transition-timing-function`, `transition-delay`. -- Шорткат `transition: all 0.3s ease`. - -### 5.2 Runtime - -- При изменении `ComputedStyle` (например, при ховере) не применять мгновенно, а запускать интерполяцию. -- Хранить `TransitionState` на элемент: `HashMap`. -- Каждый кадр обновлять transitioning-свойства. - ---- - -## 6. Новые CSS-свойства в ComputedStyle - -### 6.1 Типографика - -| Свойство | Тип | Парсер | -|----------|-----|--------| -| `font-family` | `Option` | список шрифтов | -| `font-weight` | `Option` | `normal(400)`, `bold(700)`, числовое | -| `font-style` | `Option` | `normal`, `italic`, `oblique` | -| `line-height` | `Option` | числовое или `normal` | -| `letter-spacing` | `Option` | px | -| `text-align` | `Option` | `left`, `center`, `right`, `justify` | -| `text-decoration` | `Option` | `none`, `underline`, `line-through` | -| `text-transform` | `Option` | `none`, `uppercase`, `lowercase`, `capitalize` | -| `white-space` | `Option` | `normal`, `nowrap`, `pre` | -| `word-break` | `Option` | `normal`, `break-all`, `keep-all` | -| `text-overflow` | `Option` | `clip`, `ellipsis` | - -### 6.2 Фон и границы - -| Свойство | Тип | Парсер | -|----------|-----|--------| -| `opacity` | `Option` | 0.0–1.0 | -| `background-image` | `Option` | `url(...)` | -| `background-repeat` | `Option` | `repeat`, `no-repeat` | -| `background-size` | `Option` | `cover`, `contain`, px, % | -| `background-position` | `Option` | `center`, `top left`, px | -| `linear-gradient(...)` | `Option` | парсить в `Value::Call` и обрабатывать | -| `box-shadow` | `Option>` | `offset-x offset-y blur spread color` | -| `text-shadow` | `Option>` | то же | -| `outline` | `Option` | width, style, color | -| `border-style` | `Option` | `solid`, `dashed`, `dotted` | -| `border` (шорткат) | — | разворачивать в width/style/color | - -### 6.3 Flexbox (расширение) - -| Свойство | Тип | -|----------|-----| -| `justify-content` | `Option` | `start`, `center`, `end`, `space-between`, `space-around`, `space-evenly` | -| `flex-wrap` | `Option` | `nowrap`, `wrap`, `wrap-reverse` | -| `flex-direction` | `Option` | (расширение `LayoutDirection`) | -| `align-self` | `Option` | переопределяет `align-items` для конкретного элемента | -| `align-content` | `Option` | multi-line выравнивание | -| `flex` (шорткат) | — | grow, shrink, basis | -| `flex-shrink` | `Option` | | -| `flex-basis` | `Option` | | - -### 6.4 Grid Layout - -| Свойство | Тип | -|----------|-----| -| `grid-template-columns` | `Option>` | `1fr 1fr`, `repeat(3, 1fr)`, `auto` | -| `grid-template-rows` | `Option>` | | -| `grid-gap` / `gap` | уже есть как `spacing` | | -| `grid-column` | `Option<(u32, u32)>` | start / end | -| `grid-row` | `Option<(u32, u32)>` | | -| `grid-auto-flow` | `Option` | | - -### 6.5 Позиционирование (расширение) - -| Свойство | Тип | Статус | -|----------|-----|--------| -| `position: absolute` | — | сейчас мэппится в Static | -| `position: relative` | — | сейчас мэппится в Static | -| `position: sticky` | — | сейчас мэппится в Static | -| `z-index` | `Option` | | -| `display` | `Option` | `block`, `flex`, `grid`, `none`, `inline` | - -### 6.6 Прочее - -| Свойство | Тип | -|----------|-----| -| `visibility` | `Option` | `visible`, `hidden` | -| `cursor` | `Option` | `pointer`, `default`, `text` | -| `pointer-events` | `Option` | `auto`, `none` | -| `transform` | `Option>` | `translate(x,y)`, `scale(s)`, `rotate(a)` | -| `transform-origin` | `Option` | | -| `backdrop-filter` | `Option>` | `blur(10px)`, `brightness(1.2)` | -| `filter` | `Option>` | то же | -| `list-style` | `Option` | | -| `isolation` | `Option` | `auto`, `isolate` | -| `mix-blend-mode` | `Option` | `multiply`, `screen` | - -### 6.7 Итого: ~40–60 новых полей в ComputedStyle - -Каждое поле: тип `Option`, значение по умолчанию `None`. -Парсинг: новая функция `parse_(s: &str) -> Option` для каждого. -Lookup в `ComputedStyle::compute()`. - -**Рендеринг в Iced:** -- Iced 0.14 поддерживает Background::Gradient. -- Box-shadow пока не поддерживается, но можно эмулировать через container style с offset-тенью. -- Transforms и filters — Iced пока не нативно; нужен кастомный widget или пропуск. - ---- - -## 7. Система каскада и наследования - -### 7.1 Наследование (сейчас: только `color`, `font-size`) - -Добавить наследование для: -- `font-family`, `font-weight`, `font-style`, `line-height`, `letter-spacing`, `text-align`, `white-space`, `word-break`, `text-transform`, `visibility`, `cursor`, `pointer-events`. - -Механизм: в `render_element()` передавать не только `parent_color` и `parent_font_size`, а `&ComputedStyle` родителя или отдельный `InheritedStyle`. - -### 7.2 `inherit` / `initial` / `unset` - -- Специальные значения для любого свойства. - -### 7.3 `!important` - -- Флаг важности в правиле. Переопределяет специфичность. -- Парсить `value!important`. - ---- - -## 8. CSS-функции и значения - -### 8.1 `calc()` - -```rust -enum CalcValue { - Number(f32), - Percentage(f32), - Add(Box, Box), - Sub(Box, Box), - Mul(Box, Box), - Div(Box, Box), - Var(String), -} -``` - -- Парсить `calc(100% - 20px)`. -- Вычислять в runtime с учётом контекста (размер родителя). - -### 8.2 `var()` — CSS custom properties - -- `--my-var: value;` в правилах. -- `var(--my-var, fallback)` при использовании. -- Хранить custom properties в `ComputedStyle.custom_props: HashMap`. -- Наследуются по умолчанию. - -### 8.3 `min()`, `max()`, `clamp()` - -- `min(100%, 500px)`, `max(200px, 50%)`, `clamp(200px, 50%, 500px)`. - -### 8.4 `rgb()`, `rgba()`, `hsl()`, `hsla()`, `hwb()`, `oklch()`, `color-mix()` - -- Сейчас только `#hex` и 3 named colors. -- Парсить `rgb(255, 0, 0)`, `rgba(255, 0, 0, 0.5)`. -- Расширить `parse_color()`. - -### 8.5 Named colors - -- Расширить словарь до 140+ CSS named colors (AliceBlue, ...). - ---- - -## 9. @-правила - -### 9.1 `@import` - -```glts -@import "theme.glts" -``` - -- В парсере: обработать `@import`, загрузить файл, влить переменные и миксины. -- Может быть сложным (циклы, кэширование). Опционально на раннем этапе. - -### 9.2 `@font-face` - -```glts -@font-face { - font-family: "MyFont" - src: fs:/fonts/myfont.ttf -} -``` - -- Регистрировать в Iced через `font::Family`. -- Потребует `iced::font::load()`. - -### 9.3 `@scope` (CSS Cascading Layers) - -- `@scope (.card) { ... }` — ограничение области действия правил. - ---- - -## 10. Рендеринг (renderer.rs) - -### 10.1 Псевдоклассы в рендере - -- Для интерактивных элементов передавать `button::Status`. -- `:hover`/`:active`-стили должны пересчитываться при изменении статуса. - -### 10.2 Flexbox (полноценный) - -- `justify-content`: Iced `Row`/`Column` не имеют нативного justifyContent; эмулировать через наполнители (`Length::Fill`). -- `flex-wrap`: нужен `Flow` widget или эмуляция строками. - -### 10.3 Grid - -- Полноценный CSS Grid: имплементировать кастомный Iced widget или разбивать на строки/колонки вручную. -- `grid-template-columns: 1fr 1fr 1fr` → разбивка children на ряды. -- `grid-column`/`grid-row`: позиционирование ячеек. - -### 10.4 `display: none` - -- Пропускать элемент при рендеринге (уже частично — `None` возвращается). - -### 10.5 `z-index` - -- Сортировать fixed-слой по z-index внутри stack. - -### 10.6 `position: absolute` / `relative` - -- `relative`: смещение через padding контейнера. -- `absolute`: позиционирование относительно предка с `position: relative` (или окна). Эмулировать через stack слои, как `fixed`. - -### 10.7 `position: sticky` - -- Эмулировать через Iced scrollable + перехват событий скролла. -- Пока не поддерживается Iced нативно. Можно через subscription на scroll position + ручное позиционирование. - -### 10.8 `opacity` - -- Iced: `widget.opacity(f32)` (iced 0.14+). - -### 10.9 `box-shadow`, `text-shadow` - -- Эмуляция: container с подложкой (offset background) или кастомный шейдер. -- Iced 0.14 имеет `Border` только с `color`, `width`, `radius`. Shadow — нет. - -### 10.10 `outline` - -- Через border с `outline-offset` эмуляцией. - -### 10.11 Трансформы (`transform`) - -- Iced не поддерживает transforms нативно. -- Потребуется кастомный widget с `lyon` или `vello` для path-трансформаций. -- На раннем этапе — документировать как unsupported. - ---- - -## 11. Инструментарий разработчика - -### 11.1 Вывод вычисленных стилей - -- Флаг `--debug-styles` в CLI: печатать `ComputedStyle` каждого элемента. - -### 11.2 Инспектор элементов - -- Iced debug overlay: `iced::widget::pane_grid` с инспектором. -- Показывать matched selectors, specificity, computed properties. - -### 11.3 Hot-reload стилей - -- Перекомпиляция `.glts` без перезапуска приложения. -- Обновление bytecode в runtime. - ---- - -## 12. Порядок реализации (приоритеты) - -### Фаза 1: Критическое (MVP+) -1. Структурированные селекторы + matching engine со специфичностью -2. Комбинаторы (особенно descendant) -3. Псевдоклассы `:hover`, `:active`, `:focus` -4. Селектор по ID (`#id`) -5. Множественные селекторы через запятую -6. Псевдоклассы `:first-child`, `:nth-child`, `:last-child`, `:empty` - -### Фаза 2: Визуальное обогащение -7. Новые свойства: opacity, font-weight, text-align, justify-content, line-height -8. fill-шорткаты для flex (flex-grow/shrink/basis) -9. `position: absolute` / `relative` / `sticky` -10. `z-index` -11. `display: none` -12. `calc()`, `min()`, `max()`, `clamp()` -13. `rgb()`, `rgba()`, `hsl()` + расширенный словарь named colors -14. `!important` - -### Фаза 3: Продвинутое -15. `@media` queries -16. Animations (playback) -17. Transitions -18. `box-shadow`, `text-shadow` (эмуляция) -19. CSS Grid -20. `flex-wrap` + `justify-content` полноценно -21. `var()` CSS custom properties -22. `@import` -23. `@font-face` - -### Фаза 4: Экспертное -24. `transform`, `transform-origin` -25. `backdrop-filter`, `filter` -26. `gradient` (linear, radial) -27. `color-mix()`, `oklch()` -28. Hot-reload -29. DevTools инспектор -30. `@scope` - ---- - -## 13. Архитектурные изменения - -### 13.1 `ComputedStyle` → разбить на подс-труктуры - -Вместо 40+ плоских полей: - -```rust -pub struct ComputedStyle { - pub box_model: BoxModel, - pub typography: Typography, - pub background: BackgroundStyle, - pub border: BorderStyle, - pub flex: FlexStyle, - pub grid: GridStyle, - pub position: Positioning, - pub effects: Effects, - pub overflow: OverflowStyle, - pub animation: AnimationStyle, - pub custom: HashMap, - pub display: Option, - pub visibility: Option, -} -``` - -### 13.2 Selector engine — отдельный модуль - -```rust -mod selector { - pub struct Selector { ... } - pub fn parse(input: &str) -> Result; - pub fn specificity(&self) -> (u32, u32, u32); - pub fn matches(&self, el: &Element, ctx: &MatchContext) -> bool; -} -``` - -### 13.3 StyleSheet — расширение - -```rust -pub struct StyleRule { - pub selector: Selector, - pub properties: HashMap, - pub source_order: u32, - pub media: Option, - pub important: HashSet, -} -``` - -### 13.4 Система тиков для анимаций/транзишенов - -- Новый модуль `animation` в runtime. -- `AnimationEngine` с `HashMap`. -- Iced subscription: `time::every(Duration::from_millis(16))` (60fps). - ---- - -## 14. Оценка сложности - -| Компонент | Новые файлы | Изменённые файлы | Пример LOC | -|-----------|-------------|------------------|------------| -| Selector parser | `glt/src/selector.rs` | `style_parser.rs` | ~500 | -| Selector matching | `runtime/src/selector.rs` | `mod.rs` | ~400 | -| ComputedStyle расширение | — | `style.rs` | +400 | -| Медиа-запросы | — | `style_parser.rs`, `mod.rs` | ~300 | -| Анимации | `runtime/src/animation.rs` | `style.rs`, `mod.rs`, `app.rs` | ~500 | -| Транзишены | `runtime/src/transition.rs` | | ~400 | -| Псевдоклассы | — | `mod.rs`, `renderer.rs`, `types.rs` | ~300 | -| Новые парсеры свойств | — | `style.rs` | +600 | -| Рендеринг | — | `renderer.rs` | +500 | -| Flex/Grid | `runtime/src/layout.rs` | `renderer.rs` | ~400 | -| calc/var | `runtime/src/values.rs` | `style.rs` | ~300 | -| @import/@font-face | — | `style_parser.rs`, `renderer.rs` | ~200 | -| Инструменты | `runtime/src/inspector.rs` | `cli.rs`, `app.rs` | ~300 | - -**Итого:** ~5–7 новых файлов, ~15 изменённых, ~5000–6000 строк нового кода.