@kerfjs/ui 5.0.0-beta.52 → 5.0.0-beta.53

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.
Files changed (137) hide show
  1. package/ai/component-catalog-v2.d.ts +3 -0
  2. package/ai/component-catalog-v2.json +3 -1
  3. package/ai/component-catalog-v2.schema.json +7 -0
  4. package/ai/component-catalog.json +3 -1
  5. package/ai/public-api-signatures-v1.md +12 -8
  6. package/ai/skill.md +15 -15
  7. package/ai/webawesome-jsx-signatures-v1.md +1 -1
  8. package/dist/app-tab.js +1 -1
  9. package/dist/browser/segmented-control.js +0 -1
  10. package/dist/catalog.js +4 -4
  11. package/dist/{chunk-7XJO4D6A.js → chunk-3NBL3OUQ.js} +2 -2
  12. package/dist/{chunk-7XJO4D6A.js.map → chunk-3NBL3OUQ.js.map} +1 -1
  13. package/dist/{chunk-2S7OWAEV.js → chunk-44IG7PFV.js} +3 -3
  14. package/dist/{chunk-2S7OWAEV.js.map → chunk-44IG7PFV.js.map} +1 -1
  15. package/dist/{chunk-DNCOFEUL.js → chunk-5I22LMCV.js} +2 -2
  16. package/dist/{chunk-DNCOFEUL.js.map → chunk-5I22LMCV.js.map} +1 -1
  17. package/dist/{chunk-KAQUUTZR.js → chunk-ATHXW6RP.js} +2 -2
  18. package/dist/{chunk-KAQUUTZR.js.map → chunk-ATHXW6RP.js.map} +1 -1
  19. package/dist/{chunk-JGFZ42ZF.js → chunk-BJJKFVWW.js} +14 -5
  20. package/dist/chunk-BJJKFVWW.js.map +1 -0
  21. package/dist/{chunk-T7C2VZUB.js → chunk-C2FAYFDE.js} +2 -2
  22. package/dist/{chunk-T7C2VZUB.js.map → chunk-C2FAYFDE.js.map} +1 -1
  23. package/dist/{chunk-IR53BQUJ.js → chunk-CCMKJWLX.js} +3 -3
  24. package/dist/{chunk-IR53BQUJ.js.map → chunk-CCMKJWLX.js.map} +1 -1
  25. package/dist/{chunk-SV22UIW4.js → chunk-DQA5FMOX.js} +2 -2
  26. package/dist/{chunk-SV22UIW4.js.map → chunk-DQA5FMOX.js.map} +1 -1
  27. package/dist/{chunk-LIOXPQ7N.js → chunk-GUIHMIT2.js} +12 -10
  28. package/dist/chunk-GUIHMIT2.js.map +1 -0
  29. package/dist/{chunk-3S7OUHUN.js → chunk-KPNTVB7A.js} +9 -4
  30. package/dist/chunk-KPNTVB7A.js.map +1 -0
  31. package/dist/{chunk-OSCL5TKR.js → chunk-RNZAKSME.js} +11 -8
  32. package/dist/chunk-RNZAKSME.js.map +1 -0
  33. package/dist/{chunk-ABAXNUXU.js → chunk-T22EM4ET.js} +7 -5
  34. package/dist/chunk-T22EM4ET.js.map +1 -0
  35. package/dist/{chunk-YZV2PTY4.js → chunk-TZ5IHWB2.js} +3 -3
  36. package/dist/{chunk-YZV2PTY4.js.map → chunk-TZ5IHWB2.js.map} +1 -1
  37. package/dist/{chunk-2CE22Q2K.js → chunk-WZ2GLEY4.js} +2 -1
  38. package/dist/chunk-WZ2GLEY4.js.map +1 -0
  39. package/dist/{chunk-M6GLI6A6.js → chunk-X5QSICJ3.js} +5 -5
  40. package/dist/chunk-X5QSICJ3.js.map +1 -0
  41. package/dist/{chunk-4XE2CDYB.js → chunk-ZMBU522F.js} +2 -2
  42. package/dist/{chunk-4XE2CDYB.js.map → chunk-ZMBU522F.js.map} +1 -1
  43. package/dist/css-values.d.ts +1 -1
  44. package/dist/css-values.js +1 -1
  45. package/dist/grid.js +1 -1
  46. package/dist/index.js +15 -15
  47. package/dist/list-action-row.d.ts +2 -1
  48. package/dist/list-action-row.js +1 -1
  49. package/dist/list-header.d.ts +1 -0
  50. package/dist/list-header.js +1 -1
  51. package/dist/list-item.d.ts +5 -3
  52. package/dist/list-item.js +1 -1
  53. package/dist/list.js +1 -1
  54. package/dist/nav-stack.js +1 -1
  55. package/dist/row.js +1 -1
  56. package/dist/segmented-control.d.ts +1 -1
  57. package/dist/segmented-control.js +1 -3
  58. package/dist/select.js +1 -1
  59. package/dist/skeleton.js +1 -1
  60. package/dist/spacer.js +1 -1
  61. package/dist/split-view.js +1 -1
  62. package/dist/state-banner.d.ts +1 -1
  63. package/dist/state-banner.js +1 -1
  64. package/dist/styles/badge.css +17 -6
  65. package/dist/styles/collapsible-panel.css +1 -1
  66. package/dist/styles/foundation.css +82 -26
  67. package/dist/styles/list-action-row.css +29 -8
  68. package/dist/styles/list-header.css +19 -7
  69. package/dist/styles/list-item.css +11 -3
  70. package/dist/styles/resizable-region.css +1 -1
  71. package/dist/styles/segmented-control.css +21 -1
  72. package/dist/styles/select.css +24 -13
  73. package/dist/styles/skeleton.css +33 -2
  74. package/dist/styles/state-banner.css +48 -12
  75. package/dist/styles/webawesome.css +47 -20
  76. package/dist/styles/workbench.css +1 -1
  77. package/dist/toolbar-text.js +1 -1
  78. package/dist/value-table.js +1 -1
  79. package/docs/component-contract.md +76 -4
  80. package/docs/design/templates/empty-state/with-action-dark.svg +1 -1
  81. package/docs/design/templates/empty-state-dark.svg +1 -1
  82. package/docs/design/templates/list/stack-dark.svg +1 -1
  83. package/docs/design/templates/list/stack.svg +1 -1
  84. package/docs/design/templates/list-action-row/selected.svg +1 -1
  85. package/docs/design/templates/list-action-row.svg +1 -1
  86. package/docs/design/templates/list-dark.svg +1 -1
  87. package/docs/design/templates/list-header/action-dark.svg +1 -1
  88. package/docs/design/templates/list-header/action.svg +1 -1
  89. package/docs/design/templates/list-header/count-dark.svg +1 -1
  90. package/docs/design/templates/list-header/count.svg +1 -1
  91. package/docs/design/templates/list-header/inline-action-dark.svg +1 -1
  92. package/docs/design/templates/list-header/inline-action.svg +1 -1
  93. package/docs/design/templates/list-header/toggle-expanded-dark.svg +1 -1
  94. package/docs/design/templates/list-header/toggle-expanded.svg +1 -1
  95. package/docs/design/templates/list-header-dark.svg +1 -1
  96. package/docs/design/templates/list-header.svg +1 -1
  97. package/docs/design/templates/list-item/selected.svg +1 -1
  98. package/docs/design/templates/list-item.svg +1 -1
  99. package/docs/design/templates/list.svg +1 -1
  100. package/docs/design/templates/segmented-control/equal-dark.svg +1 -1
  101. package/docs/design/templates/segmented-control/equal.svg +1 -1
  102. package/docs/design/templates/segmented-control/pill-small-dark.svg +1 -1
  103. package/docs/design/templates/segmented-control/pill-small.svg +1 -1
  104. package/docs/design/templates/segmented-control-dark.svg +1 -1
  105. package/docs/design/templates/segmented-control.svg +1 -1
  106. package/docs/design/templates/state-banner/danger-dark.svg +1 -1
  107. package/docs/design/templates/state-banner/danger.svg +1 -1
  108. package/docs/design/templates/state-banner/info-badge-dark.svg +1 -1
  109. package/docs/design/templates/state-banner/info-badge.svg +1 -1
  110. package/docs/design/templates/state-banner/info-dark.svg +1 -1
  111. package/docs/design/templates/state-banner/info.svg +1 -1
  112. package/docs/design/templates/state-banner/success-dark.svg +1 -1
  113. package/docs/design/templates/state-banner/success.svg +1 -1
  114. package/docs/design/templates/state-banner/warning-dark.svg +1 -1
  115. package/docs/design/templates/state-banner/warning.svg +1 -1
  116. package/docs/design/templates/state-banner-dark.svg +1 -1
  117. package/docs/design/templates/state-banner.svg +1 -1
  118. package/docs/design/templates/tab-bar/workspace-tabs-dark.svg +1 -1
  119. package/docs/design/templates/tab-bar/workspace-tabs.svg +1 -1
  120. package/docs/design/templates/tab-bar-dark.svg +1 -1
  121. package/docs/design/templates/tab-bar.svg +1 -1
  122. package/docs/design/templates/token-search-field/tokens.svg +1 -1
  123. package/docs/design/templates/token-search-field.svg +1 -1
  124. package/docs/design/templates.md +11 -1
  125. package/docs/device-class.md +2 -1
  126. package/docs/ux-demo.md +1 -1
  127. package/docs/webawesome-theme.md +9 -2
  128. package/llms.txt +7 -3
  129. package/package.json +1 -1
  130. package/ux-demo/recipes/loading-inspector.tsx +3 -2
  131. package/dist/chunk-2CE22Q2K.js.map +0 -1
  132. package/dist/chunk-3S7OUHUN.js.map +0 -1
  133. package/dist/chunk-ABAXNUXU.js.map +0 -1
  134. package/dist/chunk-JGFZ42ZF.js.map +0 -1
  135. package/dist/chunk-LIOXPQ7N.js.map +0 -1
  136. package/dist/chunk-M6GLI6A6.js.map +0 -1
  137. package/dist/chunk-OSCL5TKR.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,38 +1,38 @@
1
1
  export { wireTokenSearchFields } from './chunk-CMUIXJZM.js';
2
- export { ValueTable, ValueTableRow } from './chunk-2S7OWAEV.js';
2
+ export { ValueTable, ValueTableRow } from './chunk-44IG7PFV.js';
3
3
  export { wireResizableRegions } from './chunk-EKYZCRCX.js';
4
4
  export { reorderTabs, wireTabBars } from './chunk-UKKSMZYT.js';
5
5
  export { DialogSurface, PopupSurface } from './chunk-NN6GYOA2.js';
6
6
  export { TabBar } from './chunk-N3GKMPDW.js';
7
7
  export { TokenSearchField, placeTokenSearchCaret, readTokenSearchField } from './chunk-HJKRCKDR.js';
8
- export { SegmentedControl } from './chunk-M6GLI6A6.js';
9
- export { Select } from './chunk-ABAXNUXU.js';
10
- export { Spacer } from './chunk-4XE2CDYB.js';
11
- export { StateBanner } from './chunk-JGFZ42ZF.js';
8
+ export { SegmentedControl } from './chunk-X5QSICJ3.js';
9
+ export { Select } from './chunk-T22EM4ET.js';
10
+ export { Spacer } from './chunk-ZMBU522F.js';
11
+ export { StateBanner } from './chunk-BJJKFVWW.js';
12
12
  export { SunkenPanel } from './chunk-6ZXOQEAN.js';
13
13
  export { ResizableRegion, clampRegionSize, resizeRegionFromPointer } from './chunk-VOCPXGQN.js';
14
- export { Row } from './chunk-DNCOFEUL.js';
14
+ export { Row } from './chunk-5I22LMCV.js';
15
15
  export { EmptyState } from './chunk-E36EVCKG.js';
16
16
  export { FloatingToolbar } from './chunk-NDUGJ4TU.js';
17
- export { Grid } from './chunk-T7C2VZUB.js';
18
- export { ListActionRow } from './chunk-OSCL5TKR.js';
17
+ export { Grid } from './chunk-C2FAYFDE.js';
18
+ export { ListActionRow } from './chunk-RNZAKSME.js';
19
19
  export { ListInsetControl } from './chunk-D7GWXIAS.js';
20
20
  export { ListInsetText } from './chunk-ZK5EGVFP.js';
21
- export { AppTab } from './chunk-IR53BQUJ.js';
21
+ export { AppTab } from './chunk-CCMKJWLX.js';
22
22
  export { ToolbarActionLink, ToolbarControlGroup } from './chunk-ZIYOJFZD.js';
23
23
  export { Toolbar } from './chunk-MTM43SJO.js';
24
- export { ListItem } from './chunk-LIOXPQ7N.js';
25
- export { List } from './chunk-7XJO4D6A.js';
26
- export { ToolbarText } from './chunk-YZV2PTY4.js';
24
+ export { ListItem } from './chunk-GUIHMIT2.js';
25
+ export { List } from './chunk-3NBL3OUQ.js';
26
+ export { ToolbarText } from './chunk-TZ5IHWB2.js';
27
27
  export { Pane } from './chunk-7GUQYHKA.js';
28
28
 
29
29
  export { LoadingSpinner } from './chunk-ZLWQZUGF.js';
30
- export { ListHeader } from './chunk-3S7OUHUN.js';
30
+ export { ListHeader } from './chunk-KPNTVB7A.js';
31
31
  export { Text } from './chunk-7IUSV4XG.js';
32
- export { Skeleton } from './chunk-KAQUUTZR.js';
32
+ export { Skeleton } from './chunk-ATHXW6RP.js';
33
33
 
34
34
  export { Badge } from './chunk-XD7DWYXG.js';
35
- export { calc, colorVar, em, flex, foregroundColorVar, lengthVar, pct, plus, px, rem, space, uiColor } from './chunk-2CE22Q2K.js';
35
+ export { calc, colorVar, em, flex, foregroundColorVar, lengthVar, pct, plus, px, rem, space, uiColor } from './chunk-WZ2GLEY4.js';
36
36
  export { DisclosureArrow } from './chunk-HMQ2ZDGG.js';
37
37
  export { LucideIcon } from './chunk-4R777DUZ.js';
38
38
 
@@ -18,6 +18,7 @@ type ListActionRowTrailingAttributes = Readonly<Record<`data-${string}`, string
18
18
  'data-component'?: never;
19
19
  'data-action'?: never;
20
20
  'data-item-id'?: never;
21
+ 'data-kui-disabled'?: never;
21
22
  popoverTarget?: string;
22
23
  popoverTargetAction?: 'toggle' | 'show' | 'hide';
23
24
  'aria-controls'?: string;
@@ -43,7 +44,7 @@ interface ListActionRowProps {
43
44
  state?: string;
44
45
  disabled?: boolean;
45
46
  tabIndex?: number;
46
- /** Render as an unanimated loading skeleton, disabling both actions. */
47
+ /** Render as an unanimated loading skeleton, disabling both actions: label, description, icon, and status text become skeletons; the `busy` indicator stays live. */
47
48
  placeholder?: boolean;
48
49
  trailingAction: string;
49
50
  trailingActionLabel: string;
@@ -1,4 +1,4 @@
1
- export { ListActionRow } from './chunk-OSCL5TKR.js';
1
+ export { ListActionRow } from './chunk-RNZAKSME.js';
2
2
 
3
3
 
4
4
 
@@ -14,6 +14,7 @@ type ListHeaderRootAttributes = Readonly<Record<`data-${string}`, string | undef
14
14
  }>;
15
15
  type ListHeaderTriggerAttributes = Readonly<Record<`data-${string}`, string | undefined> & {
16
16
  'data-action'?: never;
17
+ 'data-kui-disabled'?: never;
17
18
  popoverTarget?: string;
18
19
  popoverTargetAction?: 'toggle' | 'show' | 'hide';
19
20
  'aria-controls'?: string;
@@ -1,4 +1,4 @@
1
- export { ListHeader } from './chunk-3S7OUHUN.js';
1
+ export { ListHeader } from './chunk-KPNTVB7A.js';
2
2
 
3
3
 
4
4
 
@@ -12,16 +12,18 @@ type ListItemRootAttributes = Readonly<Record<`data-${string}`, string | undefin
12
12
  'data-divider'?: never;
13
13
  'data-busy'?: never;
14
14
  'data-state'?: never;
15
+ 'data-kui-disabled'?: never;
15
16
  }>;
16
17
  interface ListItemProps {
17
18
  label: string | SafeHtml;
18
19
  /** App-owned supporting text rendered in the component's stable label stack. */
19
20
  description?: string | SafeHtml;
20
21
  icon?: SafeHtml;
22
+ /** Dormant author content at the row's end; a placeholder renders it as a skeleton. */
21
23
  trailing?: KerfUiContent;
22
- /** Dormant status metadata rendered before trailing content. */
24
+ /** Dormant status metadata rendered before trailing content; a placeholder renders it as a skeleton. */
23
25
  status?: string | SafeHtml;
24
- /** Show a progress indicator and expose the row as busy without replacing its content. */
26
+ /** Show a progress indicator and expose the row as busy without replacing its content; a placeholder keeps the indicator. */
25
27
  busy?: boolean;
26
28
  density?: 'standard' | 'compact';
27
29
  divider?: 'none' | 'before' | 'after' | 'both';
@@ -36,7 +38,7 @@ interface ListItemProps {
36
38
  state?: string;
37
39
  disabled?: boolean;
38
40
  tabIndex?: number;
39
- /** Render the row as an unanimated loading skeleton, disabling its action. */
41
+ /** Render the row as an unanimated loading skeleton, disabling its action: label, description, icon, status, and trailing content become skeletons; the `busy` indicator stays live. */
40
42
  placeholder?: boolean;
41
43
  rootAttributes?: ListItemRootAttributes;
42
44
  /** Native named-slot assignment when composed inside a web component. */
package/dist/list-item.js CHANGED
@@ -1,4 +1,4 @@
1
- export { ListItem } from './chunk-LIOXPQ7N.js';
1
+ export { ListItem } from './chunk-GUIHMIT2.js';
2
2
 
3
3
 
4
4
 
package/dist/list.js CHANGED
@@ -1,4 +1,4 @@
1
- export { List } from './chunk-7XJO4D6A.js';
1
+ export { List } from './chunk-3NBL3OUQ.js';
2
2
 
3
3
 
4
4
 
package/dist/nav-stack.js CHANGED
@@ -1,4 +1,4 @@
1
- export { NavStack } from './chunk-SV22UIW4.js';
1
+ export { NavStack } from './chunk-DQA5FMOX.js';
2
2
 
3
3
 
4
4
 
package/dist/row.js CHANGED
@@ -1,4 +1,4 @@
1
- export { Row } from './chunk-DNCOFEUL.js';
1
+ export { Row } from './chunk-5I22LMCV.js';
2
2
 
3
3
 
4
4
 
@@ -23,7 +23,7 @@ interface SegmentedControlProps<Value extends string = string> {
23
23
  size?: SegmentedControlSize;
24
24
  layout?: SegmentedControlLayout;
25
25
  className?: string;
26
- /** Render as an unanimated loading skeleton, disabling every segment. */
26
+ /** Render as a loading placeholder: every choice keeps its live label or icon, none is selected, and every segment is disabled. */
27
27
  placeholder?: boolean;
28
28
  /** Native named-slot assignment when composed inside a web component. */
29
29
  slot?: string;
@@ -1,5 +1,3 @@
1
- export { SegmentedControl } from './chunk-M6GLI6A6.js';
2
-
3
-
1
+ export { SegmentedControl } from './chunk-X5QSICJ3.js';
4
2
 
5
3
  //# sourceMappingURL=segmented-control.js.map
package/dist/select.js CHANGED
@@ -1,4 +1,4 @@
1
- export { Select } from './chunk-ABAXNUXU.js';
1
+ export { Select } from './chunk-T22EM4ET.js';
2
2
 
3
3
 
4
4
 
package/dist/skeleton.js CHANGED
@@ -1,4 +1,4 @@
1
- export { Skeleton } from './chunk-KAQUUTZR.js';
1
+ export { Skeleton } from './chunk-ATHXW6RP.js';
2
2
 
3
3
 
4
4
  //# sourceMappingURL=skeleton.js.map
package/dist/spacer.js CHANGED
@@ -1,4 +1,4 @@
1
- export { Spacer } from './chunk-4XE2CDYB.js';
1
+ export { Spacer } from './chunk-ZMBU522F.js';
2
2
 
3
3
 
4
4
  //# sourceMappingURL=spacer.js.map
@@ -1,4 +1,4 @@
1
- import { NavStack } from './chunk-SV22UIW4.js';
1
+ import { NavStack } from './chunk-DQA5FMOX.js';
2
2
  import { ResizableRegion } from './chunk-VOCPXGQN.js';
3
3
 
4
4
 
@@ -13,7 +13,7 @@ interface StateBannerProps {
13
13
  tone?: StateBannerTone;
14
14
  urgency?: StateBannerUrgency;
15
15
  className?: string;
16
- /** Render the title, badge, and detail as unanimated loading skeletons, keeping the icon and tone. */
16
+ /** Render the title, badge, and detail as unanimated loading skeletons, keeping the icon and tone. The detail line appears only when `detail` is set, as in the live banner. */
17
17
  placeholder?: boolean;
18
18
  /** Native named-slot assignment when composed inside a web component. */
19
19
  slot?: string;
@@ -1,4 +1,4 @@
1
- export { StateBanner } from './chunk-JGFZ42ZF.js';
1
+ export { StateBanner } from './chunk-BJJKFVWW.js';
2
2
 
3
3
 
4
4
 
@@ -27,7 +27,7 @@
27
27
  --_kui-badge-fill-quiet: var(--kui-color-brand-fill-quiet);
28
28
  --_kui-badge-fill-solid: var(--kui-color-brand-on-fill);
29
29
  --_kui-badge-border: var(--kui-color-brand-border-normal);
30
- --_kui-badge-on-quiet: var(--kui-color-brand-on-quiet);
30
+ --_kui-badge-on-quiet: var(--kui-color-brand-on-fill);
31
31
  --_kui-badge-on-solid: var(--kui-color-surface);
32
32
  }
33
33
 
@@ -35,7 +35,7 @@
35
35
  --_kui-badge-fill-quiet: var(--kui-color-pop-fill-quiet);
36
36
  --_kui-badge-fill-solid: var(--kui-color-pop-on-fill);
37
37
  --_kui-badge-border: var(--kui-color-pop-border-normal);
38
- --_kui-badge-on-quiet: var(--kui-color-pop-on-quiet);
38
+ --_kui-badge-on-quiet: var(--kui-color-pop-on-fill);
39
39
  --_kui-badge-on-solid: var(--kui-color-surface);
40
40
  }
41
41
 
@@ -43,7 +43,7 @@
43
43
  --_kui-badge-fill-quiet: var(--kui-color-success-fill-quiet);
44
44
  --_kui-badge-fill-solid: var(--kui-color-success-on-fill);
45
45
  --_kui-badge-border: var(--kui-color-success-border-normal);
46
- --_kui-badge-on-quiet: var(--kui-color-success-on-quiet);
46
+ --_kui-badge-on-quiet: var(--kui-color-success-on-fill);
47
47
  --_kui-badge-on-solid: var(--kui-color-surface);
48
48
  }
49
49
 
@@ -51,19 +51,30 @@
51
51
  --_kui-badge-fill-quiet: var(--kui-color-warning-fill-quiet);
52
52
  --_kui-badge-fill-solid: var(--kui-color-warning-on-fill);
53
53
  --_kui-badge-border: var(--kui-color-warning-border-normal);
54
- --_kui-badge-on-quiet: var(--kui-color-warning-on-quiet);
54
+ --_kui-badge-on-quiet: var(--kui-color-warning-on-fill);
55
55
  --_kui-badge-on-solid: var(--kui-color-surface);
56
56
  }
57
57
 
58
58
  .kui-badge[data-tone="danger"] {
59
59
  --_kui-badge-fill-quiet: var(--kui-color-danger-fill-quiet);
60
- --_kui-badge-fill-solid: var(--kui-color-danger-on-quiet);
60
+ --_kui-badge-fill-solid: var(--kui-color-danger-on-fill);
61
61
  --_kui-badge-border: var(--kui-color-danger-border-normal);
62
- --_kui-badge-on-quiet: var(--kui-color-danger-on-quiet);
62
+ --_kui-badge-on-quiet: var(--kui-color-danger-on-fill);
63
63
  --_kui-badge-on-solid: var(--kui-color-surface);
64
64
  }
65
65
 
66
66
  .kui-badge[data-appearance="solid"] {
67
+ /* A placeholder's skeleton inside a solid badge: the generic text-color tint
68
+ is nearly invisible on the saturated fill, so derive it from the badge's
69
+ own foreground instead, which contrasts with the fill in every tone and
70
+ color scheme. Quiet and outline badges sit on a pale fill and keep the
71
+ generic tint. */
72
+ --_kui-skeleton-fill: color-mix(
73
+ in srgb,
74
+ var(--_kui-badge-on-solid) 45%,
75
+ transparent
76
+ );
77
+
67
78
  color: var(--_kui-badge-on-solid);
68
79
  background: var(--_kui-badge-fill-solid);
69
80
  }
@@ -232,7 +232,7 @@
232
232
  .kui-collapsible-panel[data-presentation="overlay"] {
233
233
  position: fixed;
234
234
  z-index: var(--kui-collapsible-panel-overlay-z, 40);
235
- box-shadow: var(--kui-shadow-l, 0 8px 32px rgb(0 0 0 / 24%));
235
+ box-shadow: var(--kui-shadow-l);
236
236
  }
237
237
 
238
238
  [data-collapsible-overlay="true"] .kui-collapsible-panel--left,
@@ -80,13 +80,21 @@
80
80
  --kui-radius-pill: var(--wa-border-radius-pill, 999px);
81
81
  --kui-disclosure-icon-scale: 0.5;
82
82
  /* macOS Tahoe light semantics used by Hot Sheet 2, with a compatible dark extension. */
83
+ /* Every --kui-color-* token (and the focus-ring color) that reads a --wa-*
84
+ token falls back to the value src/webawesome.css assigns to that token,
85
+ including its light-dark() pair, so a page without the Web Awesome theme
86
+ resolves the same palette in both color schemes. A single light color
87
+ here would render, e.g., dark red danger text on a dark surface, and a
88
+ fallback that points at a different token (surface-raised at the surface,
89
+ text-link at the brand fill) silently diverges from the theme.
90
+ tests/browser/tone-contrast.spec.ts pins the parity for every token. */
83
91
  --kui-color-surface: var(
84
92
  --wa-color-surface-default,
85
93
  light-dark(#fff, #1c1c1e)
86
94
  );
87
95
  --kui-color-surface-raised: var(
88
96
  --wa-color-surface-raised,
89
- var(--kui-color-surface)
97
+ light-dark(#fff, #2c2c2e)
90
98
  );
91
99
  --kui-color-surface-lowered: var(
92
100
  --wa-color-surface-lowered,
@@ -99,7 +107,7 @@
99
107
  );
100
108
  --kui-color-text-link: var(
101
109
  --wa-color-text-link,
102
- var(--kui-color-brand-fill-loud)
110
+ var(--kui-color-brand-on-quiet)
103
111
  );
104
112
 
105
113
  --kui-color-neutral-fill-quiet: var(
@@ -116,7 +124,7 @@
116
124
  );
117
125
  --kui-color-neutral-border-quiet: var(
118
126
  --wa-color-neutral-border-quiet,
119
- var(--kui-color-neutral-fill-normal)
127
+ light-dark(#e5e5ea, #38383a)
120
128
  );
121
129
  --kui-color-neutral-border-normal: var(
122
130
  --wa-color-neutral-border-normal,
@@ -141,7 +149,7 @@
141
149
 
142
150
  --kui-color-brand-fill-loud: var(
143
151
  --wa-color-brand-fill-loud,
144
- light-dark(#0088ff, #64d2ff)
152
+ light-dark(#0075db, #64d2ff)
145
153
  );
146
154
  --kui-color-brand-fill-quiet: var(
147
155
  --wa-color-brand-fill-quiet,
@@ -179,21 +187,30 @@
179
187
  --wa-color-brand-border-loud,
180
188
  var(--kui-color-brand-fill-loud)
181
189
  );
190
+ /* The light brand/success/warning on-quiet values are Kerf-owned (mirrored
191
+ in src/webawesome.css): each is the Hot Sheet 2 hue darkened just enough to
192
+ clear WCAG AA (>=4.5:1) on the lowered page background (#f2f2f7), not only
193
+ on the white surface. The prior #1e6ef4 / #008932 / #a16a00 reached ~4.1:1
194
+ there. Brand #0c62f3 is 4.64:1, success #007f2e 4.62:1, warning #966200
195
+ 4.65:1 on the page (5.2:1 on white). */
182
196
  --kui-color-brand-on-quiet: var(
183
197
  --wa-color-brand-on-quiet,
184
- light-dark(#1e6ef4, #8acbff)
198
+ light-dark(#0c62f3, #8acbff)
185
199
  );
186
200
  --kui-color-brand-on-normal: var(
187
201
  --wa-color-brand-on-normal,
188
202
  var(--kui-color-brand-on-quiet)
189
203
  );
190
- --kui-color-brand-on-loud: var(--wa-color-brand-on-loud, #fff);
204
+ --kui-color-brand-on-loud: var(
205
+ --wa-color-brand-on-loud,
206
+ light-dark(#fff, #111113)
207
+ );
191
208
  /* Brand accent text placed directly ON a brand fill (quiet or normal), such as
192
209
  the info StateBanner and Select's current option. Darker than brand-on-quiet
193
- so it clears WCAG AA (>=4.5:1): brand-on-quiet (#1e6ef4) resolves to only
194
- 3.77:1 over brand-fill-normal (#d6ecff) and 4.15:1 over brand-fill-quiet
195
- (#ebf6ff), while #1a5dcf (same hue) clears ~4.9:1 and ~5.2:1 there. The dark
196
- value matches brand-on-quiet, which already passes over the dark fills. */
210
+ so it clears WCAG AA (>=4.5:1): brand-on-quiet (#0c62f3) resolves to only
211
+ 4.26:1 over brand-fill-normal (#d6ecff), while #1a5dcf (same hue) clears
212
+ ~4.9:1 there and ~5.5:1 over brand-fill-quiet (#ebf6ff). The dark value
213
+ matches brand-on-quiet, which already passes over the dark fills. */
197
214
  --kui-color-brand-on-fill: light-dark(#1a5dcf, #8acbff);
198
215
 
199
216
  /* Pop is attractive emphasis without status meaning: use it for featured,
@@ -266,12 +283,19 @@
266
283
  var(--kui-color-neutral-on-normal)
267
284
  )
268
285
  );
269
- --kui-color-success-on-quiet: var(--wa-color-success-on-quiet, #008932);
270
- --kui-color-success-on-normal: var(--wa-color-success-on-normal, #006d28);
271
- --kui-color-success-on-loud: var(--wa-color-success-on-loud, #fff);
286
+ --kui-color-success-on-quiet: var(
287
+ --wa-color-success-on-quiet,
288
+ light-dark(#007f2e, #63e685)
289
+ );
290
+ --kui-color-success-on-normal: var(
291
+ --wa-color-success-on-normal,
292
+ light-dark(#006d28, #8cea9f)
293
+ );
294
+ --kui-color-success-on-loud: var(--wa-color-success-on-loud, #1d1d1f);
272
295
  /* Success text placed ON a success fill (e.g. the success StateBanner). Darker
273
- than success-on-quiet so it clears WCAG AA (>=4.5:1) over success-fill-quiet
274
- (#e3f7e8), where #008932 reached only 4.05:1. Dark matches success-on-quiet. */
296
+ than success-on-quiet for margin over success-fill-quiet (#e3f7e8): the
297
+ original on-quiet #008932 reached only 4.05:1 there and today's #007f2e sits
298
+ at 4.60:1, while #00792c clears ~5:1. Dark matches success-on-quiet. */
275
299
  --kui-color-success-on-fill: light-dark(#00792c, #63e685);
276
300
 
277
301
  --kui-color-warning-fill-loud: var(--wa-color-warning-fill-loud, #ffcc00);
@@ -315,15 +339,25 @@
315
339
  var(--kui-color-neutral-on-normal)
316
340
  )
317
341
  );
318
- --kui-color-warning-on-quiet: var(--wa-color-warning-on-quiet, #a16a00);
319
- --kui-color-warning-on-normal: var(--wa-color-warning-on-normal, #5f3f00);
342
+ --kui-color-warning-on-quiet: var(
343
+ --wa-color-warning-on-quiet,
344
+ light-dark(#966200, #ffd84a)
345
+ );
346
+ --kui-color-warning-on-normal: var(
347
+ --wa-color-warning-on-normal,
348
+ light-dark(#5f3f00, #ffe27a)
349
+ );
320
350
  --kui-color-warning-on-loud: var(--wa-color-warning-on-loud, #1d1d1f);
321
351
  /* Warning text placed ON a warning fill (e.g. the warning StateBanner). Darker
322
- than warning-on-quiet so it clears WCAG AA (>=4.5:1) over warning-fill-quiet
323
- (#fffae8), where #a16a00 reached only 4.39:1. Dark matches warning-on-quiet. */
352
+ than warning-on-quiet for margin over warning-fill-quiet (#fffae8): the
353
+ original on-quiet #a16a00 reached only 4.39:1 there (today's #966200 is
354
+ 4.97:1), while #8f5e00 clears ~5.3:1. Dark matches warning-on-quiet. */
324
355
  --kui-color-warning-on-fill: light-dark(#8f5e00, #ffd84a);
325
356
 
326
- --kui-color-danger-fill-loud: var(--wa-color-danger-fill-loud, #ff383c);
357
+ --kui-color-danger-fill-loud: var(
358
+ --wa-color-danger-fill-loud,
359
+ light-dark(#eb0005, #ff383c)
360
+ );
327
361
  --kui-color-danger-fill-quiet: var(
328
362
  --wa-color-danger-fill-quiet,
329
363
  color-mix(
@@ -364,9 +398,26 @@
364
398
  var(--kui-color-neutral-on-normal)
365
399
  )
366
400
  );
367
- --kui-color-danger-on-quiet: var(--wa-color-danger-on-quiet, #c20b20);
368
- --kui-color-danger-on-normal: var(--wa-color-danger-on-normal, #8e0717);
369
- --kui-color-danger-on-loud: var(--wa-color-danger-on-loud, #fff);
401
+ --kui-color-danger-on-quiet: var(
402
+ --wa-color-danger-on-quiet,
403
+ light-dark(#c20b20, #ff696c)
404
+ );
405
+ --kui-color-danger-on-normal: var(
406
+ --wa-color-danger-on-normal,
407
+ light-dark(#8e0717, #ff8a8c)
408
+ );
409
+ --kui-color-danger-on-loud: var(
410
+ --wa-color-danger-on-loud,
411
+ light-dark(#fff, #111113)
412
+ );
413
+ /* Danger text placed ON a danger fill (e.g. the danger StateBanner) and the
414
+ danger Badge's solid fill. The light value matches danger-on-quiet, which
415
+ already clears WCAG AA (5.7:1) over danger-fill-quiet. The dark value is
416
+ lighter than danger-on-quiet (#ff696c), which reached only 5.7:1 over the
417
+ dark fill-quiet (4.0:1 as dimmed banner detail) and left the solid badge's
418
+ dark text and placeholder skeleton the weakest of any tone on a mid-red
419
+ fill; #ffa0a2 matches the other tones' pale dark on-fill values. */
420
+ --kui-color-danger-on-fill: light-dark(#c20b20, #ffa0a2);
370
421
 
371
422
  /* Compatibility aliases retained for existing @kerfjs/ui consumers. */
372
423
  --kui-color-border: var(
@@ -386,12 +437,17 @@
386
437
  --kui-color-danger-text: var(--kui-color-danger-on-quiet);
387
438
  --kui-focus-ring: var(
388
439
  --wa-focus-ring,
389
- 3px solid var(--wa-color-focus, var(--kui-color-brand-fill-loud))
440
+ 3px solid var(--wa-color-focus, light-dark(#007aff, #64d2ff))
441
+ );
442
+ /* Elevation mirrors webawesome.css's scheme-aware shadows: dark raises the
443
+ alpha so a raised surface still separates from a near-black page. */
444
+ --kui-shadow-s: var(
445
+ --wa-shadow-s,
446
+ 0 1px 3px light-dark(rgb(0 0 0 / 0.14), rgb(0 0 0 / 0.5))
390
447
  );
391
- --kui-shadow-s: var(--wa-shadow-s, 0 1px 3px rgb(0 0 0 / 0.14));
392
448
  --kui-shadow-l: var(
393
449
  --wa-shadow-l,
394
- 0 0.75rem 2rem rgb(0 0 0 / 0.09)
450
+ 0 0.75rem 2rem light-dark(rgb(0 0 0 / 0.09), rgb(0 0 0 / 0.32))
395
451
  );
396
452
  }
397
453
 
@@ -45,7 +45,9 @@
45
45
  border-end-end-radius: 0;
46
46
  }
47
47
 
48
- .kui-list-action-row:has(.kui-list-action-row__primary:hover) {
48
+ .kui-list-action-row:not([data-placeholder="true"]):has(
49
+ .kui-list-action-row__primary:hover
50
+ ) {
49
51
  --kui-list-action-row-border: var(--kui-list-action-row-hover-border);
50
52
  --kui-list-action-row-background: var(--kui-list-action-row-hover-background);
51
53
  }
@@ -92,12 +94,27 @@
92
94
  outline: none;
93
95
  }
94
96
 
95
- .kui-list-action-row__primary:disabled,
96
- .kui-list-action-row__trailing-action:disabled {
97
- cursor: not-allowed;
97
+ /* A placeholder is disabled to stay inert, but it is loading, not unavailable:
98
+ it keeps the live row's tone (see the placeholder rule in skeleton.css). The
99
+ disabled tone follows the author's disabled props (the data-kui-disabled
100
+ marker), so a disabled button's placeholder is dimmed like the loaded one;
101
+ only the `not-allowed` cursor is reserved for the live row. */
102
+ .kui-list-action-row
103
+ :is(
104
+ .kui-list-action-row__primary,
105
+ .kui-list-action-row__trailing-action
106
+ )[data-kui-disabled="true"] {
98
107
  opacity: 0.58;
99
108
  }
100
109
 
110
+ .kui-list-action-row:not([data-placeholder="true"])
111
+ :is(
112
+ .kui-list-action-row__primary:disabled,
113
+ .kui-list-action-row__trailing-action:disabled
114
+ ) {
115
+ cursor: not-allowed;
116
+ }
117
+
101
118
  .kui-list-action-row__icon {
102
119
  position: absolute;
103
120
  inset-block-start: 50%;
@@ -144,6 +161,9 @@
144
161
 
145
162
  .kui-list-action-row__status {
146
163
  display: inline-flex;
164
+ /* A full line even when it holds only a placeholder skeleton, which is
165
+ shorter than the text line it stands in for. */
166
+ min-block-size: 1lh;
147
167
  align-items: center;
148
168
  gap: 0.25rem;
149
169
  }
@@ -180,10 +200,11 @@
180
200
  opacity: 0;
181
201
  }
182
202
 
183
- .kui-list-action-row[data-trailing-visibility="interaction"]:is(
184
- :hover,
185
- :focus-within
186
- )
203
+ /* A placeholder is inert, so hovering it reveals nothing: the trailing action
204
+ keeps the live resting state (hidden until interaction). */
205
+ .kui-list-action-row[data-trailing-visibility="interaction"]:not(
206
+ [data-placeholder="true"]
207
+ ):is(:hover, :focus-within)
187
208
  .kui-list-action-row__trailing-action {
188
209
  opacity: 1;
189
210
  }
@@ -187,8 +187,13 @@
187
187
  flex: none;
188
188
  }
189
189
 
190
- .kui-list-header__action:hover,
191
- .kui-list-header__toggle:hover {
190
+ /* A placeholder is disabled to stay inert, but it is loading, not unavailable:
191
+ it keeps the live tone and gives no hover feedback (see the placeholder rule
192
+ in skeleton.css). A disabled control gives none either. */
193
+ .kui-list-header:not([data-placeholder="true"])
194
+ .kui-list-header__action:hover:not(:disabled),
195
+ .kui-list-header:not([data-placeholder="true"])
196
+ .kui-list-header__toggle:hover:not(:disabled) {
192
197
  border-color: var(--kui-color-neutral-border-normal);
193
198
  background: var(--kui-list-header-hover-background);
194
199
  }
@@ -199,14 +204,21 @@
199
204
  outline-offset: 1px;
200
205
  }
201
206
 
202
- .kui-list-header__action:disabled {
203
- cursor: not-allowed;
207
+ /* The disabled tone follows the author's `actionDisabled` (the
208
+ data-kui-disabled marker), so a disabled action or toggle's placeholder is
209
+ dimmed like the loaded one; only the `not-allowed` cursor is reserved for
210
+ the live header. The tone is the component's own, never Web Awesome's
211
+ native `button:disabled`, so it holds without webawesome.css. */
212
+ .kui-list-header__action[data-kui-disabled="true"],
213
+ .kui-list-header__toggle[data-kui-disabled="true"] {
204
214
  opacity: 0.48;
205
215
  }
206
216
 
207
- .kui-list-header__action:disabled:hover {
208
- border-color: transparent;
209
- background: transparent;
217
+ .kui-list-header:not([data-placeholder="true"])
218
+ .kui-list-header__action:disabled,
219
+ .kui-list-header:not([data-placeholder="true"])
220
+ .kui-list-header__toggle:disabled {
221
+ cursor: not-allowed;
210
222
  }
211
223
 
212
224
  .kui-list-header__action > svg,
@@ -78,17 +78,25 @@
78
78
  grid-column: 2;
79
79
  }
80
80
 
81
- .kui-list-item:hover {
81
+ .kui-list-item:hover:not([data-placeholder="true"]) {
82
82
  border-color: var(--kui-list-item-hover-border);
83
83
  background: var(--kui-list-item-hover-background);
84
84
  }
85
85
 
86
- .kui-list-item:disabled {
86
+ /* A placeholder is disabled to stay inert, but it is loading, not unavailable:
87
+ it keeps the live row's tone (see the placeholder rule in skeleton.css). The
88
+ disabled tone follows the author's `disabled` prop (the data-kui-disabled
89
+ marker), so a disabled row's placeholder is dimmed like the loaded row; only
90
+ the `not-allowed` cursor is reserved for the live row. */
91
+ .kui-list-item[data-kui-disabled="true"] {
87
92
  color: var(--kui-color-neutral-on-quiet);
88
- cursor: not-allowed;
89
93
  opacity: 0.58;
90
94
  }
91
95
 
96
+ .kui-list-item:disabled:not([data-placeholder="true"]) {
97
+ cursor: not-allowed;
98
+ }
99
+
92
100
  .kui-list-item[aria-current="page"],
93
101
  .kui-list-item[aria-pressed="true"] {
94
102
  border-color: var(--kui-list-item-selected-border);
@@ -152,7 +152,7 @@
152
152
  z-index: var(--kui-resizable-region-overlay-z, 41);
153
153
  max-width: var(--kui-resizable-region-overlay-max-width, 85vw);
154
154
  max-height: var(--kui-resizable-region-overlay-max-height, 85vh);
155
- box-shadow: var(--kui-shadow-l, 0 8px 32px rgb(0 0 0 / 24%));
155
+ box-shadow: var(--kui-shadow-l);
156
156
  }
157
157
  .kui-resizable-region[data-presentation="overlay"][data-axis="horizontal"] {
158
158
  inset-block: 0;