Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/site/src/content/en/changelog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Significant changes may continue until v1.0 is released, so all notable changes
- For components added with `lism-cli ui add` before v0.26.0, change `@layer lism-component` to `lism-block` in their `_style.css`.
- **Breaking:** Removed the deprecated component aliases `SideMain` / `FluidCols` / `SwitchCols` and the `Dummy` component from `lism-css/react` and `lism-css/astro`. Migrate to `WithSide` / `AutoColumns` / `SwitchColumns` and `DummyText` from `@lism-css/ui`, respectively (#646).
- **Breaking:** Removed `_propConfig`, which overrode the Lism Props conversion settings per prop, from `getLismProps` and component props. To change the conversion settings, use [`props` in `lism.config.js`](/en/docs/customize/config/) instead (#225).
- `@lism-css/ui`: Fixed `lism-base` styles taking priority over `b--*` styles when component CSS is output before `lism-css/main.css` (for example, a `Button` rendered as an `a` element kept its underline and link color). Each component's CSS and `style.css` now declare the order of `lism-base` and `lism-block` at the top (#644).

<Divider bds="dashed" my="40" />

Expand Down
1 change: 1 addition & 0 deletions apps/site/src/content/ja/changelog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ v1.0のリリースまでは大きな変更が続く可能性があるため、
- v0.26.0より前に`lism-cli ui add`で追加したコンポーネントは、`_style.css`の`@layer lism-component`を`lism-block`へ書き換えてください。
- **破壊的変更:** 非推奨だったコンポーネントエイリアス`SideMain` / `FluidCols` / `SwitchCols`と`Dummy`コンポーネントを、`lism-css/react`と`lism-css/astro`から削除しました。それぞれ`WithSide` / `AutoColumns` / `SwitchColumns`と`@lism-css/ui`の`DummyText`へ移行してください(#646)。
- **破壊的変更:** Lism Propsの変換設定をprop単位で上書きする`_propConfig`を、`getLismProps`と各コンポーネントのpropsから削除しました。変換設定を変えたい場合は、[`lism.config.js`の`props`](/docs/customize/config/)で設定してください(#225)。
- `@lism-css/ui`: コンポーネントのCSSが`lism-css/main.css`より前に出力されると、`lism-base`のスタイルが`b--*`のスタイルより優先される不具合を修正しました(`a`要素の`Button`に下線とリンク色が残るなど)。各コンポーネントのCSSと`style.css`の先頭で、`lism-base`と`lism-block`の順序を宣言します(#644)。

<Divider bds="dashed" my="40" />

Expand Down
12 changes: 11 additions & 1 deletion docs/decisions.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
基準日: 2026-09-28・コミットc9321bcec
基準日: 2026-09-29・コミット4aa2aa5c6

# 意思決定の記録

## 2026-09-29: `@lism-css/ui`のコンポーネントCSSは先頭で`lism-base, lism-block`の順序だけを宣言する

各コンポーネントは自分の`_style.css`をimportしており、そのCSSの出力位置は利用側のバンドラが決める。`lism-css/main.css`より前に出力されると`lism-block`が最初のレイヤーとして登録され、`lism-base`より弱くなる(#644)。`a`要素の`Button`に下線とリンク色が残った。

- 決定: `packages/lism-ui/src/components/*/_style.css`の各先頭に`@layer lism-base, lism-block;`を置き、全ファイルにあることをテストで検査する。`@layer`文は登録済みのレイヤーの位置を変えず、未登録のレイヤーを宣言順に後ろへ足す。先頭の2層を固定すれば、後から読まれる`main.css`の宣言で残りの層が正しい順に並ぶ。ui側のCSSが使うレイヤーは`lism-block`だけ。
- 却下: 6層すべてを宣言する案。レイヤーを増減するたびにui側も直すことになる(`lism-component`の削除がその例)。
- 却下: コンポーネント側のCSSの自動読み込みをやめ、`style.css`に一本化する案。利用者に`style.css`の読み込みを求める破壊的変更になり、使うコンポーネントのCSSだけを読み込む利点も失う。
- 却下: ビルド時に`dist`のCSSへ宣言を付与する案。Astro版は`src`の`_style.css`を読むため効かない。
- 決定: `dist/style.css`は全コンポーネントの`_style.css`を結合するため、同じ宣言がコンポーネントの数だけ入る。`packages/lism-ui/build-css.js`がコンパイル後に先頭の1つだけ残し、1つも無ければビルドを失敗させる。共有の`compileCssTree`と`dist/components/*/_style.css`は変えない。

## 2026-09-28: 後方互換用の`lism-component`レイヤーを削除する

v0.26.0で`c--`を`b--`へ移行したとき(#546, #559)、旧`c--`の配置先だった`lism-component`は宣言だけ残した。宣言から消すと、利用者CSSの`@layer lism-component`が初出の位置で登録され、優先度が変わるため。空のレイヤーが公開文書の6層の表記と食い違うという報告があり、v1へ持ち越さずに互換を切る。
Expand Down
17 changes: 17 additions & 0 deletions packages/lism-ui/build-css.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
// P1 で bin/build-css.js(compileSCSS)は共有コアへ統合された。
Expand All @@ -7,13 +8,29 @@ import { compileCssTree } from '@lism-css/plugin/builder';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const LAYER_ORDER_PATTERN = /@layer\s+lism-base\s*,\s*lism-block\s*;/g;

// style.css は全コンポーネントの _style.css を結合するため、同じ順序宣言が重複する。先頭の1つだけ残す。
function dedupeLayerOrder(cssPath) {
const css = fs.readFileSync(cssPath, 'utf8');

let count = 0;
const deduped = css.replace(LAYER_ORDER_PATTERN, (match) => (count++ === 0 ? match : ''));
if (count === 0) {
throw new Error(`[build-css] ${path.relative(__dirname, cssPath)} にレイヤー順序宣言が見つかりません`);
}

fs.writeFileSync(cssPath, deduped);
}

// デフォルトエクスポート(他から await 可能)
async function buildCSS() {
// パス(絶対パスに変換)
const scssDir = path.resolve(__dirname, './src');
const distDir = path.resolve(__dirname, './dist/');

await compileCssTree({ scssDir, distDir });
dedupeLayerOrder(path.resolve(distDir, 'style.css'));
}

buildCSS();
1 change: 1 addition & 0 deletions packages/lism-ui/src/components/Accordion/_style.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@layer lism-base, lism-block;
@layer lism-block {
.b--accordion {
--duration: var(--acc-duration, 0.25s);
Expand Down
1 change: 1 addition & 0 deletions packages/lism-ui/src/components/Alert/_style.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@layer lism-base, lism-block;
@layer lism-block {
/* Note: u--cbox との併用を前提としています。layout="withSide" 指定時は l--withSide がレイアウトを上書きします. */
.b--alert {
Expand Down
1 change: 1 addition & 0 deletions packages/lism-ui/src/components/Avatar/_style.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@layer lism-base, lism-block;
@layer lism-block {
/* src ありの通常時: l--frame との併用が前提 */
.b--avatar {
Expand Down
1 change: 1 addition & 0 deletions packages/lism-ui/src/components/Badge/_style.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@layer lism-base, lism-block;
@layer lism-block {
.b--badge {
--c: var(--base);
Expand Down
1 change: 1 addition & 0 deletions packages/lism-ui/src/components/Button/_style.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@layer lism-base, lism-block;
@layer lism-block {
.b--button {
--c: var(--base);
Expand Down
1 change: 1 addition & 0 deletions packages/lism-ui/src/components/Callout/_style.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@layer lism-base, lism-block;
@layer lism-block {
/* Note: l--stack と u--cbox との併用を前提としています. */
.b--callout {
Expand Down
1 change: 1 addition & 0 deletions packages/lism-ui/src/components/Details/_style.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@layer lism-base, lism-block;
/* ::details-content と grid-template-rows: 0fr → 1fr のトランジションでアニメーション */
@layer lism-block {
.b--details {
Expand Down
1 change: 1 addition & 0 deletions packages/lism-ui/src/components/Modal/_style.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@layer lism-base, lism-block;
/*
* dialog で実装.
* Memo: ::backdrop のアニメーションはFirefoxで動かない
Expand Down
1 change: 1 addition & 0 deletions packages/lism-ui/src/components/NavMenu/_style.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@layer lism-base, lism-block;
@layer lism-block {
.b--navMenu {
--link-td: none;
Expand Down
1 change: 1 addition & 0 deletions packages/lism-ui/src/components/Popover/_style.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@layer lism-base, lism-block;
/*
* ネイティブ Popover API(popover 属性)で開閉し、CSS Anchor Positioning で配置する。
* anchor 配置は @supports で囲い、非対応ブラウザ(部分対応の Chrome 128〜130 を含む)には
Expand Down
1 change: 1 addition & 0 deletions packages/lism-ui/src/components/ShapeDivider/_style.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@layer lism-base, lism-block;
/* Note: scale 反転は、__inner に対して行う。shapeDivider自身を反転させると、X方向に隙間ができてしまう。 */
@layer lism-block {
.b--shapeDivider {
Expand Down
1 change: 1 addition & 0 deletions packages/lism-ui/src/components/Tabs/_style.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@layer lism-base, lism-block;
@layer lism-block {
/* l--grid との併用が前提 */
.b--tabs {
Expand Down
1 change: 1 addition & 0 deletions packages/lism-ui/src/components/Tooltip/_style.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@layer lism-base, lism-block;
/*
* 表示は CSS(:hover / :focus-visible)、配置は CSS Anchor Positioning。
* anchor 配置は @supports で囲い、非対応(部分対応の Chrome 128〜130 含む)はルート基準の absolute 配置に落とす。
Expand Down
25 changes: 25 additions & 0 deletions packages/lism-ui/src/components/styleLayerOrder.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { existsSync, readdirSync, readFileSync } from 'node:fs';
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { describe, expect, it } from 'vitest';

const componentsDir = dirname(fileURLToPath(import.meta.url));

// バンドラがコンポーネントCSSを lism-css/main.css より前に出力しても、lism-block が lism-base より後ろになるよう先頭で順序を固定する
const LAYER_ORDER = /^@layer lism-base, lism-block;\r?\n/;

const styleFiles = readdirSync(componentsDir, { withFileTypes: true })
.filter((entry) => entry.isDirectory())
.map((entry) => `${entry.name}/_style.css`)
.filter((file) => existsSync(resolve(componentsDir, file)));

describe('コンポーネントCSSのレイヤー順序宣言', () => {
it('検査対象の _style.css が見つかる', () => {
expect(styleFiles.length).toBeGreaterThan(0);
});

it.each(styleFiles)('%s の先頭に順序宣言がある', (file) => {
const css = readFileSync(resolve(componentsDir, file), 'utf8');
expect(css).toMatch(LAYER_ORDER);
});
});
Loading