Встраивание в чужую страницу
Что будет с чужой страницей вокруг листа: её шрифт, фон и прокрутка.

В рамке выше работает тот самый проект, чей код лежит ниже, — собранный, но не переписанный: те же файлы, только пропущенные через сборку. Считает в нём не ядро, а дублёр транспорта, поэтому числа в ячейках ничего не значат: смотреть нужно на код.
Страница, которую открывает браузер.
<!doctype html><!-- Встраивание в чужую страницу — НАСТОЯЩИЙ МАЛЕНЬКИЙ ПРОЕКТ.
Не «страница витрины», а тот проект, который встраивающий копирует к себе целиком. Галерея примеров ЗАПУСКАЕТ эти файлы и ПОКАЗЫВАЕТ их же.--><html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title>Встраивание в чужую страницу — @f1</title> </head> <body> <!-- ВСЁ ВОКРУГ ЛИСТА ПРИНАДЛЕЖИТ ХОЗЯИНУ: шрифт, фон, отступы, прокрутка. Стили этой страницы нарочно НЕ наши — иначе проверка невмешательства проверяла бы саму себя. --> <div data-example="embedded" class="host-page"> <h1 class="host-title">Отчёт за квартал</h1> <p class="host-text"> Ниже — таблица, встроенная в эту страницу. Всё вокруг принадлежит хосту: шрифт, фон, отступы и прокрутка документа. </p> <div class="host-box"> <!-- Лист живёт в ОТВЕДЁННОЙ ему коробке и не растекается по документу. --> <div id="app" data-embed-box style="height: 420px; display: flex; flex-direction: column"></div> </div> <p class="host-text"> Текст после таблицы — он обязан остаться на месте, а страница — прокручиваться. </p> <!-- Хвост нужен, чтобы у страницы была СВОЯ прокрутка: без неё проверка «лист не забрал прокрутку документа» ничего не проверяет. --> <div style="height: 1200px"></div> </div>
<script type="module" src="./src/main.ts"></script> </body></html>Точка входа: здесь лист создаётся и сюда же приходят события.
import { createSheetsCore } from "@f1/preset-sheets-core";import { transport } from "./book.js";import { hostAsks } from "./host.js";import "./styles.css";
/** * ВСТРАИВАНИЕ В ЧУЖУЮ СТРАНИЦУ. * * Проверяется не картинка, а НЕВМЕШАТЕЛЬСТВО: страница остаётся * прокручиваемой, её заголовок — своим шрифтом, а лист живёт в отведённой ему * коробке. Ради этого и затевались теневые корни: оформление листа наружу не * течёт, а оформление хозяина внутрь не попадает. * * Единственное, что лист берёт у страницы, — УЗЕЛ. Своей страницы он не * заводит, корень документа не забирает и прокрутку не отнимает. */const { locale } = hostAsks();
const core = createSheetsCore({ mount: document.getElementById("app")!, transport, locale,});
import.meta.hot?.dispose(() => core.destroy());Книга примера: данные, с которыми лист открывается.
import { createMockTransport } from "@f1/contract";
/** * КНИГА-ЗАГЛУШКА — ВМЕСТО НАСТОЯЩЕГО ЯДРА. * * Транспорт контракта — единственное место, где лист разговаривает с ядром * (инвариант №1: считает ядро, оболочка только показывает). В продукте здесь * стоит `wasm` или мост хоста, и меняется РОВНО эта строка — всё остальное в * проекте остаётся как есть. */export const transport = createMockTransport({ cellAt: (row, col) => (col === 0 ? `строка ${row + 1}` : `${(row + 1) * (col + 1)}`),});Сторона хозяина страницы: что приложение отвечает листу и что от него получает.
import { applyLocaleAttributes, resolveLocale, setLocale, type Locale } from "@f1/i18n";
/** * ЧТО ХОЗЯИН СТРАНИЦЫ ДАЁТ ЛИСТУ — тема и язык. * * У встраивающего это уже есть своё: тему он знает из настроек, язык — из * профиля пользователя. Здесь и то и другое читается из адреса * (`?theme=dark&locale=ar`) ровно затем, чтобы на любое состояние можно было * дать ссылку и чтобы его проверял обход: настройка, доступная только щелчком, * недоступна ни ссылке, ни автоматической проверке. * * ПРИЗНАКИ СТАВЯТСЯ НА КОРЕНЬ ДОКУМЕНТА — потому что это делает ХОЗЯИН, а не * лист. Лист читает тему оттуда, где стоит (`:host-context`), а язык получает * СВОЙСТВОМ сборки: два листа на одной странице вправе говорить на разном. * * НАПРАВЛЕНИЕ ПИСЬМА — ИНТЕРФЕЙСА, А НЕ ДОКУМЕНТА. `dir="rtl"` зеркалит хром * страницы; «Лист справа налево» из Excel — свойство КНИГИ, и сетка от * арабского языка интерфейса не переворачивается. Это не пропуск, а решение * (`locale.ts`). */export function hostAsks(): { readonly theme: "light" | "dark"; readonly locale: Locale } { const params = new URLSearchParams(location.search); const theme = params.get("theme") === "dark" ? "dark" : "light"; const locale = resolveLocale(params.get("locale") ?? undefined, "ru");
document.documentElement.setAttribute("data-theme", theme); /* Язык — один на процесс: словарь модульный, и ставит его хозяин страницы. */ setLocale(locale); applyLocaleAttributes(document.documentElement, locale);
return { theme, locale };}Оформление страницы вокруг листа.
/* ЛИСТ СТИЛЕЙ НАБОРА КОМПОНЕНТОВ — ЕДИНСТВЕННАЯ СТРОКА, КОТОРУЮ НЕЛЬЗЯ ЗАБЫТЬ. Собственное оформление лист приносит в теневые корни сам, но утилиты раскладки, которыми он держит свои органы, компилируются ЭТИМ листом. Без него страница не просто выглядит иначе — вкладка ЗАВИСАЕТ (бесконечный цикл замера у сетки без размеров). У потребителя вне репозитория это `@fastoffices/formula-kit` из его node_modules. */@import "@fastoffices/formula-kit"; /* см. примечание выше *//* * СТИЛИ ЧУЖОЙ СТРАНИЦЫ — НАМЕРЕННО НЕ НАШИ. * * Эта страница обязана выглядеть как сайт, который про нас ничего не знает: * своя гарнитура, свой фон, свои отступы. Будь она собрана нашим набором, * доказательство невмешательства проверяло бы само себя. */body { margin: 0;}
.host-page { font-family: Georgia, "Times New Roman", serif; background: #fdf6e3; color: #3b3b3b; padding: 32px 48px; min-height: 100vh;}
:root[data-theme="dark"] .host-page { background: #221f1a; color: #e0d8c6;}
.host-title { font-size: 32px; margin: 0 0 12px;}
.host-text { font-size: 17px; line-height: 1.6; max-width: 60ch;}
.host-box { border: 2px solid #d8c9a3; border-radius: 8px; overflow: hidden; margin: 24px 0; background: #fff;}
:root[data-theme="dark"] .host-box { border-color: #4a4235; background: #1b1b1b;}Из каких пакетов собран пример.
{ "name": "f1-example-embedded", "private": true, "type": "module", "description": "Лист внутри чужой страницы: её шрифт, фон и прокрутка остаются её.", "scripts": { "dev": "vite", "build": "vite build" }, "dependencies": { "@f1/preset-sheets-core": "*", "@f1/contract": "*", "@f1/i18n": "*" }, "devDependencies": { "vite": "^7.0.0" }}- Остальные примеры — Примеры F1.
- Правила, на которые ссылается код, — пять правил.
- Из чего собирается лист — Архитектура.
- Что можно вызвать сегодня — справочник Compute Contract.