ksk-design-system 1.65.0 → 1.66.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -0
- package/bin/lint.js +183 -0
- package/contracts/components.json +1 -1
- package/contracts/rules.json +2 -2
- package/contracts/token-hex-cache.json +1 -1
- package/dist/index.js +11 -10
- package/dist/native/ui.js +16 -11
- package/dist/types/components/patterns/stat-card.d.ts +3 -4
- package/dist/types/native/components/SearchBar.d.ts +8 -2
- package/package.json +1 -1
- package/src/styles/source-safelist.css +1 -0
package/README.md
CHANGED
|
@@ -229,6 +229,22 @@ consumer が shadcn 既定の `src/components/ui/` に部品を置いても中
|
|
|
229
229
|
(v1.63.x までは単一の `excludes` をパスと行内容の両方に OR で当てていたため、
|
|
230
230
|
このディレクトリ名だけで 13 ルールが同時に黙っていました)。
|
|
231
231
|
|
|
232
|
+
`excludeLines` の各値は **literal 文字列**として `line.includes(value)` で判定されます
|
|
233
|
+
(正規表現ではありません)。`shadow-\[` のように正規表現エスケープした値を書くと、実ソースの
|
|
234
|
+
`shadow-[var(--shadow-md)]` と一致せず除外が一度も効きません(issue #463)。
|
|
235
|
+
`scripts/check-rules-contract.mjs`(`npm run check` に組み込み済み)が `excludeLines` /
|
|
236
|
+
`excludePaths` / `excludeDsPaths` 内のバックスラッシュ混入を検出します。
|
|
237
|
+
|
|
238
|
+
#### P029: テンプレートリテラル className の許容範囲(issue #464)
|
|
239
|
+
|
|
240
|
+
`className={\`...\${...}...\`}` の補間部(`${...}`)が**文字列リテラルのみで構成される式**
|
|
241
|
+
(単純三項 `cond ? "a" : "b"` / `&&` / ネスト三項)なら、Tailwind の静的クラス抽出を壊さないため
|
|
242
|
+
P029 の対象外です。CLAUDE.md の実装前セルフチェックにある「クラス名は完全な文字列で書く。分岐は
|
|
243
|
+
三項演算子か cva variant で」という方針と一致させています。
|
|
244
|
+
|
|
245
|
+
識別子・関数呼び出し・メンバーアクセスの補間(`` `bg-${color}` `` 等)や、テンプレートリテラルの
|
|
246
|
+
入れ子は静的抽出できないため引き続き検出します。`cn()` / `clsx()` / CVA を使ってください。
|
|
247
|
+
|
|
232
248
|
### Jest(CommonJS)でコンポーネントをテストする
|
|
233
249
|
|
|
234
250
|
このパッケージは **ESM-only** です。CJS との dual build は配布せず、Jest
|
package/bin/lint.js
CHANGED
|
@@ -789,6 +789,7 @@ function lintFile(file, cwd, rules, options = {}) {
|
|
|
789
789
|
if (matchesRuleExclude(rule, { file: rel, line: rawLine, isDsFile })) continue
|
|
790
790
|
const maskedLine = maskedLines[index] ?? ""
|
|
791
791
|
if (!regex.test(maskedLine)) continue
|
|
792
|
+
if (rule.id === "P029" && isP029TemplateLiteralExempt(rawLine)) continue
|
|
792
793
|
if (ignores.suppresses(rule.id ?? "UNKNOWN", index + 1)) continue
|
|
793
794
|
findings.push(toFinding(rule, rel, index + 1, platform))
|
|
794
795
|
}
|
|
@@ -1119,6 +1120,188 @@ function maskTemplateLiterals(source) {
|
|
|
1119
1120
|
return maskStrings(source, TEMPLATE_DELIMITER_ONLY)
|
|
1120
1121
|
}
|
|
1121
1122
|
|
|
1123
|
+
/**
|
|
1124
|
+
* P029(テンプレートリテラル className 禁止)の例外判定(issue #464)。
|
|
1125
|
+
*
|
|
1126
|
+
* `className={\`base ${cond ? "a" : "b"}\`}` のように、補間部(`${...}`)が
|
|
1127
|
+
* 「文字列リテラルのみで構成される式」(三項・&&・ネスト三項を含む)なら
|
|
1128
|
+
* Tailwind の静的クラス抽出を壊さないため対象外にする。`${color}` のような
|
|
1129
|
+
* 識別子・関数呼び出し・メンバーアクセスの補間は従来どおり検出する。
|
|
1130
|
+
*
|
|
1131
|
+
* 文字列一致ベースの簡易パーサーであり、TypeScript の完全な式パーサーではない。
|
|
1132
|
+
* 判定に迷うケース(バッククォートのネスト等)は安全側=「例外にしない」を返す。
|
|
1133
|
+
*/
|
|
1134
|
+
|
|
1135
|
+
/** 文字列/括弧の深さを見ながら、depth 0 の `?` `:` `&&` `||` の位置を集める */
|
|
1136
|
+
function scanTopLevelOperatorTokens(expr) {
|
|
1137
|
+
const tokens = []
|
|
1138
|
+
let depth = 0
|
|
1139
|
+
let quote = null
|
|
1140
|
+
for (let i = 0; i < expr.length; i++) {
|
|
1141
|
+
const ch = expr[i]
|
|
1142
|
+
if (quote) {
|
|
1143
|
+
if (ch === "\\") {
|
|
1144
|
+
i += 1
|
|
1145
|
+
continue
|
|
1146
|
+
}
|
|
1147
|
+
if (ch === quote) quote = null
|
|
1148
|
+
continue
|
|
1149
|
+
}
|
|
1150
|
+
if (ch === '"' || ch === "'") {
|
|
1151
|
+
quote = ch
|
|
1152
|
+
continue
|
|
1153
|
+
}
|
|
1154
|
+
if (ch === "(" || ch === "[" || ch === "{") {
|
|
1155
|
+
depth += 1
|
|
1156
|
+
continue
|
|
1157
|
+
}
|
|
1158
|
+
if (ch === ")" || ch === "]" || ch === "}") {
|
|
1159
|
+
depth -= 1
|
|
1160
|
+
continue
|
|
1161
|
+
}
|
|
1162
|
+
if (depth !== 0) continue
|
|
1163
|
+
if (ch === "?") tokens.push({ index: i, type: "?" })
|
|
1164
|
+
else if (ch === ":") tokens.push({ index: i, type: ":" })
|
|
1165
|
+
else if (ch === "&" && expr[i + 1] === "&") {
|
|
1166
|
+
tokens.push({ index: i, type: "&&" })
|
|
1167
|
+
i += 1
|
|
1168
|
+
} else if (ch === "|" && expr[i + 1] === "|") {
|
|
1169
|
+
tokens.push({ index: i, type: "||" })
|
|
1170
|
+
i += 1
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
return tokens
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
/** `cond ? a : b` を depth 0 の `?`/`:` のバランスで分割する(ネスト三項対応) */
|
|
1177
|
+
function splitTopLevelTernary(expr) {
|
|
1178
|
+
const tokens = scanTopLevelOperatorTokens(expr)
|
|
1179
|
+
const questionIndex = tokens.findIndex((token) => token.type === "?")
|
|
1180
|
+
if (questionIndex === -1) return null
|
|
1181
|
+
let balance = 1
|
|
1182
|
+
for (let i = questionIndex + 1; i < tokens.length; i++) {
|
|
1183
|
+
if (tokens[i].type === "?") balance += 1
|
|
1184
|
+
else if (tokens[i].type === ":") {
|
|
1185
|
+
balance -= 1
|
|
1186
|
+
if (balance === 0) {
|
|
1187
|
+
const questionPos = tokens[questionIndex].index
|
|
1188
|
+
const colonPos = tokens[i].index
|
|
1189
|
+
return {
|
|
1190
|
+
whenTrue: expr.slice(questionPos + 1, colonPos),
|
|
1191
|
+
whenFalse: expr.slice(colonPos + 1),
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
return null
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
/** `lhs && rhs` / `lhs || rhs` を最初の depth 0 演算子で分割する */
|
|
1200
|
+
function splitTopLevelLogical(expr) {
|
|
1201
|
+
const token = scanTopLevelOperatorTokens(expr).find(
|
|
1202
|
+
(candidate) => candidate.type === "&&" || candidate.type === "||",
|
|
1203
|
+
)
|
|
1204
|
+
if (!token) return null
|
|
1205
|
+
return { rhs: expr.slice(token.index + token.type.length) }
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
function isStringLiteralExpr(expr) {
|
|
1209
|
+
const trimmed = expr.trim()
|
|
1210
|
+
return /^"(?:[^"\\]|\\.)*"$/.test(trimmed) || /^'(?:[^'\\]|\\.)*'$/.test(trimmed)
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
/** `(expr)` のように括弧が式全体をちょうど一度だけ包んでいるか */
|
|
1214
|
+
function isFullyParenWrapped(expr) {
|
|
1215
|
+
if (expr[0] !== "(" || expr[expr.length - 1] !== ")") return false
|
|
1216
|
+
let depth = 0
|
|
1217
|
+
for (let i = 0; i < expr.length; i++) {
|
|
1218
|
+
if (expr[i] === "(") depth += 1
|
|
1219
|
+
else if (expr[i] === ")") {
|
|
1220
|
+
depth -= 1
|
|
1221
|
+
if (depth === 0) return i === expr.length - 1
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
return false
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
/** 補間式が「文字列リテラルのみで構成される式」か(issue #464) */
|
|
1228
|
+
export function isLiteralOnlyInterpolation(expr) {
|
|
1229
|
+
const trimmed = (expr ?? "").trim()
|
|
1230
|
+
if (trimmed === "") return false
|
|
1231
|
+
// ネストしたテンプレートリテラルは判定を諦めて安全側(=対象外にしない)に倒す
|
|
1232
|
+
if (trimmed.includes("`")) return false
|
|
1233
|
+
if (isStringLiteralExpr(trimmed)) return true
|
|
1234
|
+
if (isFullyParenWrapped(trimmed)) return isLiteralOnlyInterpolation(trimmed.slice(1, -1))
|
|
1235
|
+
const ternary = splitTopLevelTernary(trimmed)
|
|
1236
|
+
if (ternary) {
|
|
1237
|
+
return isLiteralOnlyInterpolation(ternary.whenTrue) && isLiteralOnlyInterpolation(ternary.whenFalse)
|
|
1238
|
+
}
|
|
1239
|
+
const logical = splitTopLevelLogical(trimmed)
|
|
1240
|
+
if (logical) return isLiteralOnlyInterpolation(logical.rhs)
|
|
1241
|
+
return false
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
/** テンプレートリテラル(バッククォート開始位置つき)の中身を取り出す。同一行内で閉じない場合は null */
|
|
1245
|
+
function extractTemplateLiteralBody(line, backtickIndex) {
|
|
1246
|
+
let i = backtickIndex + 1
|
|
1247
|
+
let braceDepth = 0
|
|
1248
|
+
let content = ""
|
|
1249
|
+
while (i < line.length) {
|
|
1250
|
+
const ch = line[i]
|
|
1251
|
+
if (ch === "\\") {
|
|
1252
|
+
content += ch + (line[i + 1] ?? "")
|
|
1253
|
+
i += 2
|
|
1254
|
+
continue
|
|
1255
|
+
}
|
|
1256
|
+
if (braceDepth === 0 && ch === "`") return content
|
|
1257
|
+
if (ch === "{") braceDepth += 1
|
|
1258
|
+
else if (ch === "}" && braceDepth > 0) braceDepth -= 1
|
|
1259
|
+
content += ch
|
|
1260
|
+
i += 1
|
|
1261
|
+
}
|
|
1262
|
+
return null
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
/** テンプレートリテラルの中身から `${...}` の中身だけを depth バランスで取り出す */
|
|
1266
|
+
function extractInterpolationExprs(content) {
|
|
1267
|
+
const exprs = []
|
|
1268
|
+
let i = content.indexOf("${")
|
|
1269
|
+
while (i !== -1) {
|
|
1270
|
+
const start = i + 2
|
|
1271
|
+
let depth = 1
|
|
1272
|
+
let j = start
|
|
1273
|
+
while (j < content.length && depth > 0) {
|
|
1274
|
+
if (content[j] === "{") depth += 1
|
|
1275
|
+
else if (content[j] === "}") depth -= 1
|
|
1276
|
+
j += 1
|
|
1277
|
+
}
|
|
1278
|
+
if (depth === 0) {
|
|
1279
|
+
exprs.push(content.slice(start, j - 1))
|
|
1280
|
+
i = content.indexOf("${", j)
|
|
1281
|
+
} else {
|
|
1282
|
+
exprs.push(content.slice(start))
|
|
1283
|
+
break
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
return exprs
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
/**
|
|
1290
|
+
* P029 が fire した行が「className の template literal で、補間部が全て
|
|
1291
|
+
* 文字列リテラルのみで構成される式」なら true(=対象外にしてよい)を返す。
|
|
1292
|
+
*/
|
|
1293
|
+
export function isP029TemplateLiteralExempt(line) {
|
|
1294
|
+
const classNameIndex = line.indexOf("className=")
|
|
1295
|
+
if (classNameIndex === -1) return false
|
|
1296
|
+
const backtickIndex = line.indexOf("`", classNameIndex)
|
|
1297
|
+
if (backtickIndex === -1) return false
|
|
1298
|
+
const content = extractTemplateLiteralBody(line, backtickIndex)
|
|
1299
|
+
if (content === null) return false
|
|
1300
|
+
const interpolations = extractInterpolationExprs(content)
|
|
1301
|
+
if (interpolations.length === 0) return false
|
|
1302
|
+
return interpolations.every((expr) => isLiteralOnlyInterpolation(expr))
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1122
1305
|
function excludeList(value) {
|
|
1123
1306
|
return Array.isArray(value) ? value : []
|
|
1124
1307
|
}
|
package/contracts/rules.json
CHANGED
|
@@ -228,7 +228,7 @@
|
|
|
228
228
|
"pattern": "shadow-md\\b|shadow-lg\\b|shadow-xl\\b|shadow-2xl\\b",
|
|
229
229
|
"excludePaths": [".stories."],
|
|
230
230
|
"excludeDsPaths": ["components/ui/", "components/patterns/"],
|
|
231
|
-
"excludeLines": ["shadow
|
|
231
|
+
"excludeLines": ["shadow-["],
|
|
232
232
|
"message": "DS 定義外のシャドウ禁止",
|
|
233
233
|
"fix": "shadow-[var(--shadow-sm/md/lg/dialog/tooltip)]"
|
|
234
234
|
},
|
|
@@ -269,7 +269,7 @@
|
|
|
269
269
|
"severity": "warning",
|
|
270
270
|
"category": "accessibility",
|
|
271
271
|
"appliesTo": ["dom"],
|
|
272
|
-
"pattern": "<div
|
|
272
|
+
"pattern": "<div\\b(?:(?!<|>)[\\s\\S])*?\\sonClick\\b|<span\\b(?:(?!<|>)[\\s\\S])*?\\sonClick\\b",
|
|
273
273
|
"excludePaths": [".stories."],
|
|
274
274
|
"excludeLines": [],
|
|
275
275
|
"message": "<div onClick> 禁止(キーボード操作・スクリーンリーダー不可)",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"meta": {
|
|
3
3
|
"name": "KSK Design System — Semantic Token Hex Cache",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.66.1",
|
|
5
5
|
"description": "semantic / semanticDark トークン(var(--Primitive-*) 参照)を実 hex に解決したサイドカー生成物。hex はデフォルト(Blue)テーマでの解決値であり、Brand 系(meta.themeDependentKeys に列挙)はテーマ差し替え(orange/green/violet 等)で実色が変わる。テーマ別の完全解決値は `ksk-design-system/native` エクスポート(バンドル済み native トークンモジュール)の themes を参照。tokens.json 本体のスキーマは変更せず、AI がこのファイルだけで実色を把握できるようにし、primitive 値の変更による semantic 実色のドリフトを --check で機械検出する。",
|
|
6
6
|
"generatedBy": "scripts/generate-token-hex-cache.mjs",
|
|
7
7
|
"theme": "default",
|
package/dist/index.js
CHANGED
|
@@ -11439,16 +11439,21 @@ function Fu({ images: e, indicatorType: t = "thumbnail", aspectRatio: n = "4/3",
|
|
|
11439
11439
|
className: G("flex flex-col gap-2", i),
|
|
11440
11440
|
children: [
|
|
11441
11441
|
/* @__PURE__ */ V("div", {
|
|
11442
|
-
className: G("relative w-full overflow-hidden rounded-xl bg-[var(--Surface-Tertiary)] cursor-pointer", Pu[n] ?? "aspect-[4/3]"),
|
|
11442
|
+
className: G("relative w-full overflow-hidden rounded-xl bg-[var(--Surface-Tertiary)]", r && "cursor-pointer", Pu[n] ?? "aspect-[4/3]"),
|
|
11443
11443
|
onTouchStart: m,
|
|
11444
11444
|
onTouchEnd: h,
|
|
11445
|
-
onClick: () => r?.(c),
|
|
11446
11445
|
children: [
|
|
11447
11446
|
g && /* @__PURE__ */ B("img", {
|
|
11448
11447
|
src: g.src,
|
|
11449
11448
|
alt: g.alt ?? s(c),
|
|
11450
11449
|
className: "w-full h-full object-cover transition-opacity duration-[var(--Motion-Duration-Base)]"
|
|
11451
11450
|
}, c),
|
|
11451
|
+
r && /* @__PURE__ */ B("button", {
|
|
11452
|
+
type: "button",
|
|
11453
|
+
className: "absolute inset-0 z-0 h-full w-full cursor-pointer appearance-none",
|
|
11454
|
+
"aria-label": s(c),
|
|
11455
|
+
onClick: () => r(c)
|
|
11456
|
+
}),
|
|
11452
11457
|
e.length > 1 && /* @__PURE__ */ V("span", {
|
|
11453
11458
|
className: "absolute bottom-2 right-2 bg-[var(--Overlay-Medium)] text-[var(--Text-on-Media)] typo-label-xs px-2 py-0.5 rounded-full",
|
|
11454
11459
|
children: [
|
|
@@ -13727,18 +13732,14 @@ var df = {
|
|
|
13727
13732
|
};
|
|
13728
13733
|
function ff({ className: e, label: t, value: n, unit: r, trend: i, icon: a, variant: o = "default", interactive: s, onClick: c, ...l }) {
|
|
13729
13734
|
let u = df[o], d = s ?? !!c;
|
|
13730
|
-
return /* @__PURE__ */ V("div", {
|
|
13735
|
+
return /* @__PURE__ */ V(d ? "button" : "div", {
|
|
13736
|
+
type: d ? "button" : void 0,
|
|
13731
13737
|
"data-slot": "stat-card",
|
|
13732
13738
|
"data-variant": o,
|
|
13733
13739
|
"data-interactive": d || void 0,
|
|
13734
|
-
role: d ? "button" : void 0,
|
|
13735
|
-
tabIndex: d ? 0 : void 0,
|
|
13736
13740
|
onClick: d ? c : void 0,
|
|
13737
|
-
|
|
13738
|
-
|
|
13739
|
-
} : void 0,
|
|
13740
|
-
className: G("flex flex-col gap-2 rounded-lg border border-[var(--Border-Low-Emphasis)] p-4 shadow-[var(--shadow-md)]", u.card, d && [
|
|
13741
|
-
"cursor-pointer transition-all",
|
|
13741
|
+
className: G("flex flex-col gap-2 rounded-lg border border-[var(--Border-Low-Emphasis)] p-4 text-left shadow-[var(--shadow-md)]", u.card, d && [
|
|
13742
|
+
"w-full appearance-none cursor-pointer transition-all",
|
|
13742
13743
|
u.hoverBg,
|
|
13743
13744
|
"active:scale-[0.98]",
|
|
13744
13745
|
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--Focus-High-Emphasis)] focus-visible:ring-offset-2"
|
package/dist/native/ui.js
CHANGED
|
@@ -5839,21 +5839,21 @@ function xi({ banners: e, itemWidth: t, height: n = 160, showIndicator: r = !0 }
|
|
|
5839
5839
|
}
|
|
5840
5840
|
//#endregion
|
|
5841
5841
|
//#region src/native/components/SearchBar.tsx
|
|
5842
|
-
function Si({ value: e, onChange: t, placeholder: n = "検索", onSubmit: r, onClear: i, autoFocus: a }) {
|
|
5843
|
-
let { theme:
|
|
5842
|
+
function Si({ value: e, onChange: t, placeholder: n = "検索", onSubmit: r, onClear: i, autoFocus: a, accessibilityLabel: o, accessibilityHint: s, accessibilityRole: c, accessibilityState: l, ...u }) {
|
|
5843
|
+
let { theme: d, scales: f } = G();
|
|
5844
5844
|
return /* @__PURE__ */ D(H, {
|
|
5845
5845
|
style: {
|
|
5846
5846
|
flexDirection: "row",
|
|
5847
5847
|
alignItems: "center",
|
|
5848
|
-
gap:
|
|
5849
|
-
paddingHorizontal:
|
|
5848
|
+
gap: f.spacing.scale[2],
|
|
5849
|
+
paddingHorizontal: f.spacing.scale[3],
|
|
5850
5850
|
height: 44,
|
|
5851
|
-
backgroundColor:
|
|
5852
|
-
borderRadius:
|
|
5851
|
+
backgroundColor: d.surface.secondary,
|
|
5852
|
+
borderRadius: f.borderRadius.full
|
|
5853
5853
|
},
|
|
5854
5854
|
children: [
|
|
5855
5855
|
/* @__PURE__ */ E(B, {
|
|
5856
|
-
style: [Y("label.md"), { color:
|
|
5856
|
+
style: [Y("label.md"), { color: d.text["low-emphasis"] }],
|
|
5857
5857
|
children: "🔍"
|
|
5858
5858
|
}),
|
|
5859
5859
|
/* @__PURE__ */ E(V, {
|
|
@@ -5861,12 +5861,17 @@ function Si({ value: e, onChange: t, placeholder: n = "検索", onSubmit: r, onC
|
|
|
5861
5861
|
onChangeText: t,
|
|
5862
5862
|
onSubmitEditing: r,
|
|
5863
5863
|
placeholder: n,
|
|
5864
|
-
placeholderTextColor:
|
|
5864
|
+
placeholderTextColor: d.text["low-emphasis"],
|
|
5865
5865
|
returnKeyType: "search",
|
|
5866
5866
|
autoFocus: a,
|
|
5867
|
+
accessibilityLabel: o ?? n,
|
|
5868
|
+
accessibilityHint: s,
|
|
5869
|
+
accessibilityRole: c,
|
|
5870
|
+
accessibilityState: l,
|
|
5871
|
+
...u,
|
|
5867
5872
|
style: [Y("body.md"), {
|
|
5868
5873
|
flex: 1,
|
|
5869
|
-
color:
|
|
5874
|
+
color: d.text["high-emphasis"],
|
|
5870
5875
|
paddingVertical: 0
|
|
5871
5876
|
}]
|
|
5872
5877
|
}),
|
|
@@ -5880,12 +5885,12 @@ function Si({ value: e, onChange: t, placeholder: n = "検索", onSubmit: r, onC
|
|
|
5880
5885
|
width: 20,
|
|
5881
5886
|
height: 20,
|
|
5882
5887
|
borderRadius: 10,
|
|
5883
|
-
backgroundColor:
|
|
5888
|
+
backgroundColor: d.surface.tertiary,
|
|
5884
5889
|
alignItems: "center",
|
|
5885
5890
|
justifyContent: "center"
|
|
5886
5891
|
},
|
|
5887
5892
|
children: /* @__PURE__ */ E(B, {
|
|
5888
|
-
style: [Y("label.xs"), { color:
|
|
5893
|
+
style: [Y("label.xs"), { color: d.text["medium-emphasis"] }],
|
|
5889
5894
|
children: "×"
|
|
5890
5895
|
})
|
|
5891
5896
|
})
|
|
@@ -20,10 +20,9 @@ interface StatCardProps extends Omit<React.ComponentProps<"div">, "onClick"> {
|
|
|
20
20
|
*/
|
|
21
21
|
variant?: StatCardVariant;
|
|
22
22
|
/**
|
|
23
|
-
* Interactive モード: true にすると card
|
|
24
|
-
* -
|
|
25
|
-
* -
|
|
26
|
-
* - hover で軽い陰り、cursor-pointer
|
|
23
|
+
* Interactive モード: true にすると card が実 `<button>` として描画される。
|
|
24
|
+
* - ネイティブ button のフォーカスリング・キーボード操作(Enter/Space)を自動付与
|
|
25
|
+
* - hover で軽い陰り、cursor-pointer、active:scale
|
|
27
26
|
*
|
|
28
27
|
* onClick だけ渡しても interactive=true 扱いする。
|
|
29
28
|
*/
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
|
|
2
|
+
import { type AccessibilityProps } from "react-native";
|
|
3
|
+
/**
|
|
4
|
+
* `AccessibilityProps` を継承しているため、`accessibilityLabel` /
|
|
5
|
+
* `accessibilityHint` / `accessibilityState` / `accessibilityRole` を
|
|
6
|
+
* そのまま渡せる(issue #465)。内部の `TextInput` へそのまま転送する。
|
|
7
|
+
*/
|
|
8
|
+
export interface SearchBarProps extends AccessibilityProps {
|
|
3
9
|
value: string;
|
|
4
10
|
onChange: (value: string) => void;
|
|
5
11
|
placeholder?: string;
|
|
@@ -7,4 +13,4 @@ export interface SearchBarProps {
|
|
|
7
13
|
onClear?: () => void;
|
|
8
14
|
autoFocus?: boolean;
|
|
9
15
|
}
|
|
10
|
-
export declare function SearchBar({ value, onChange, placeholder, onSubmit, onClear, autoFocus, }: SearchBarProps): React.JSX.Element;
|
|
16
|
+
export declare function SearchBar({ value, onChange, placeholder, onSubmit, onClear, autoFocus, accessibilityLabel, accessibilityHint, accessibilityRole, accessibilityState, ...accessibilityProps }: SearchBarProps): React.JSX.Element;
|
package/package.json
CHANGED
|
@@ -100,6 +100,7 @@
|
|
|
100
100
|
@source inline("animate-in");
|
|
101
101
|
@source inline("animate-pulse");
|
|
102
102
|
@source inline("animate-spin");
|
|
103
|
+
@source inline("appearance-none");
|
|
103
104
|
@source inline("aria-disabled:opacity-50");
|
|
104
105
|
@source inline("aria-invalid:border-[var(--Border-Caution)]");
|
|
105
106
|
@source inline("aria-invalid:ring-[var(--Caution-Base)]/20");
|