@mitcsutt/kiln-ui 0.3.0 → 0.5.0

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 (112) hide show
  1. package/dist/components/actions/Button/Button.module.js.map +1 -1
  2. package/dist/components/actions/ToggleChip/ToggleChip.d.ts +5 -0
  3. package/dist/components/actions/ToggleChip/ToggleChip.js +10 -6
  4. package/dist/components/actions/ToggleChip/ToggleChip.js.map +1 -1
  5. package/dist/components/actions/ToggleChip/chip.module.js +4 -3
  6. package/dist/components/actions/ToggleChip/chip.module.js.map +1 -1
  7. package/dist/components/display/AvatarGroup/AvatarGroup.d.ts +2 -2
  8. package/dist/components/display/AvatarGroup/AvatarGroup.js +1 -1
  9. package/dist/components/display/AvatarGroup/AvatarGroup.js.map +1 -1
  10. package/dist/components/display/Card/Card.d.ts +7 -4
  11. package/dist/components/display/Card/Card.js +8 -7
  12. package/dist/components/display/Card/Card.js.map +1 -1
  13. package/dist/components/display/Card/Card.module.js.map +1 -1
  14. package/dist/components/display/List/List.d.ts +18 -5
  15. package/dist/components/display/List/List.js +53 -43
  16. package/dist/components/display/List/List.js.map +1 -1
  17. package/dist/components/display/List/List.module.js.map +1 -1
  18. package/dist/components/display/List/index.d.ts +1 -1
  19. package/dist/components/display/Marquee/Marquee.js +1 -1
  20. package/dist/components/display/Marquee/Marquee.js.map +1 -1
  21. package/dist/components/display/Media/Media.d.ts +15 -0
  22. package/dist/components/display/Media/Media.js +43 -23
  23. package/dist/components/display/Media/Media.js.map +1 -1
  24. package/dist/components/display/Media/Media.module.js.map +1 -1
  25. package/dist/components/display/Media/index.d.ts +1 -1
  26. package/dist/components/display/Stat/Stat.module.js.map +1 -1
  27. package/dist/components/display/Table/Table.d.ts +23 -1
  28. package/dist/components/display/Table/Table.js +19 -14
  29. package/dist/components/display/Table/Table.js.map +1 -1
  30. package/dist/components/display/Table/Table.module.js.map +1 -1
  31. package/dist/components/display/Table/index.d.ts +1 -1
  32. package/dist/components/display/Tag/Tag.d.ts +3 -0
  33. package/dist/components/display/Tag/Tag.js +11 -10
  34. package/dist/components/display/Tag/Tag.js.map +1 -1
  35. package/dist/components/display/Tag/Tag.module.js.map +1 -1
  36. package/dist/components/display/Tag/index.d.ts +1 -1
  37. package/dist/components/feedback/Flash/Flash.d.ts +47 -0
  38. package/dist/components/feedback/Flash/Flash.js +36 -0
  39. package/dist/components/feedback/Flash/Flash.js.map +1 -0
  40. package/dist/components/feedback/Flash/Flash.module.js +10 -0
  41. package/dist/components/feedback/Flash/Flash.module.js.map +1 -0
  42. package/dist/components/feedback/Flash/index.d.ts +2 -0
  43. package/dist/components/feedback/RelativeTime/RelativeTime.d.ts +7 -0
  44. package/dist/components/feedback/RelativeTime/RelativeTime.js +11 -11
  45. package/dist/components/feedback/RelativeTime/RelativeTime.js.map +1 -1
  46. package/dist/components/feedback/StatusDot/StatusDot.d.ts +1 -1
  47. package/dist/components/feedback/StatusDot/StatusDot.js.map +1 -1
  48. package/dist/components/inputs/ChoiceCards/ChoiceCards.js +9 -9
  49. package/dist/components/inputs/Combobox/Combobox.js +5 -5
  50. package/dist/components/inputs/PasswordInput/PasswordInput.js +4 -4
  51. package/dist/components/layout/AppShell/AppShell.d.ts +4 -1
  52. package/dist/components/layout/AppShell/AppShell.js +58 -44
  53. package/dist/components/layout/AppShell/AppShell.js.map +1 -1
  54. package/dist/components/layout/AppShell/AppShell.module.js.map +1 -1
  55. package/dist/components/layout/Box/Box.d.ts +15 -3
  56. package/dist/components/layout/Box/Box.js +11 -10
  57. package/dist/components/layout/Box/Box.js.map +1 -1
  58. package/dist/components/layout/Box/Box.module.js.map +1 -1
  59. package/dist/components/layout/Divider/Divider.d.ts +7 -1
  60. package/dist/components/layout/Divider/Divider.js +18 -20
  61. package/dist/components/layout/Divider/Divider.js.map +1 -1
  62. package/dist/components/layout/ScrollArea/ScrollArea.d.ts +36 -0
  63. package/dist/components/layout/ScrollArea/ScrollArea.js +25 -0
  64. package/dist/components/layout/ScrollArea/ScrollArea.js.map +1 -0
  65. package/dist/components/layout/ScrollArea/ScrollArea.module.js +6 -0
  66. package/dist/components/layout/ScrollArea/ScrollArea.module.js.map +1 -0
  67. package/dist/components/layout/ScrollArea/index.d.ts +2 -0
  68. package/dist/components/layout/Section/Section.d.ts +18 -7
  69. package/dist/components/layout/Section/Section.js +10 -9
  70. package/dist/components/layout/Section/Section.js.map +1 -1
  71. package/dist/components/layout/Section/Section.module.js.map +1 -1
  72. package/dist/components/navigation/Accordion/Accordion.d.ts +6 -1
  73. package/dist/components/navigation/Accordion/Accordion.js +19 -11
  74. package/dist/components/navigation/Accordion/Accordion.js.map +1 -1
  75. package/dist/components/navigation/Accordion/Accordion.module.js +7 -6
  76. package/dist/components/navigation/Accordion/Accordion.module.js.map +1 -1
  77. package/dist/components/navigation/NavLinks/NavLinks.d.ts +4 -1
  78. package/dist/components/navigation/NavLinks/NavLinks.js.map +1 -1
  79. package/dist/components/navigation/NavLinks/NavLinks.module.js.map +1 -1
  80. package/dist/components/overlays/Tooltip/Tooltip.d.ts +23 -0
  81. package/dist/components/overlays/Tooltip/Tooltip.js +77 -31
  82. package/dist/components/overlays/Tooltip/Tooltip.js.map +1 -1
  83. package/dist/components/typography/Numeral/Numeral.d.ts +26 -2
  84. package/dist/components/typography/Numeral/Numeral.js +25 -21
  85. package/dist/components/typography/Numeral/Numeral.js.map +1 -1
  86. package/dist/components/typography/Numeral/Numeral.module.js +4 -3
  87. package/dist/components/typography/Numeral/Numeral.module.js.map +1 -1
  88. package/dist/components/typography/Text/Text.d.ts +5 -2
  89. package/dist/components/typography/Text/Text.js.map +1 -1
  90. package/dist/components/typography/Text/Text.module.js.map +1 -1
  91. package/dist/icons/Icon.js +1 -0
  92. package/dist/icons/Icon.js.map +1 -1
  93. package/dist/icons/icons.d.ts +12 -0
  94. package/dist/icons/icons.js +63 -13
  95. package/dist/icons/icons.js.map +1 -1
  96. package/dist/index.d.ts +19 -24
  97. package/dist/index.js +114 -112
  98. package/dist/styles.css +1 -1
  99. package/dist/themes/fiesta.css +1 -1
  100. package/dist/utils/tokens.d.ts +2 -0
  101. package/dist/utils/tokens.js.map +1 -1
  102. package/package.json +2 -2
  103. package/skills/custom-theme/SKILL.md +1 -1
  104. package/skills/design-rules/SKILL.md +8 -4
  105. package/skills/layout-composition/SKILL.md +2 -0
  106. package/skills/layout-composition/references/app-shell.md +2 -2
  107. package/skills/layout-composition/references/box.md +21 -1
  108. package/skills/layout-composition/references/divider.md +30 -1
  109. package/skills/layout-composition/references/scroll-area.md +68 -0
  110. package/skills/layout-composition/references/section.md +24 -2
  111. package/skills/setup-and-theming/SKILL.md +3 -3
  112. package/skills/setup-and-theming/references/fiesta.md +1 -1
@@ -1 +1 @@
1
- @layer kiln.reset,kiln.tokens;@layer kiln.themes{[data-theme=fiesta]{--font-display:"Big Shoulders", "Arial Narrow", ui-sans-serif, sans-serif;--font-text:"Bricolage Grotesque", ui-sans-serif, system-ui, sans-serif;--font-prose:"Bricolage Grotesque", ui-sans-serif, system-ui, sans-serif;--font-mono:"Martian Mono", ui-monospace, Menlo, monospace;--font-numeric:"Big Shoulders", "Arial Narrow", ui-sans-serif, sans-serif;--type-base:1rem;--display-scale:1;--type-ratio:1.28;--display-weight:850;--display-style:normal;--display-stretch:100%;--display-transform:uppercase;--display-tracking:.005em;--display-opsz:72;--heading-font:var(--font-display);--heading-weight:800;--heading-tracking:.01em;--heading-transform:uppercase;--label-weight:650;--label-tracking:0;--label-transform:none;--numeric-stretch:100%;--numeral-weight:600;--numeral-scale:1.12;--mono-stretch:75%;--table-head-font:var(--font-display);--leading-tight:.9;--leading-snug:1.1;--leading-body:1.5;--prose-size:1.0625rem;--prose-leading:1.55;--density:.92;--motion-scale:.9;--ease-out:cubic-bezier(.22, 1, .36, 1);--ease-in-out:cubic-bezier(.65, 0, .35, 1);--ease-spring:cubic-bezier(.34, 1.56, .64, 1);--icon-stroke:2.25;--border-width:2px;--border-width-strong:3px;--radius-action:999px;--radius-field:.75rem;--radius-surface:1.125rem;--radius-media:.75rem;--radius-chip:999px;--radius-avatar:50%;--color-canvas:light-dark(oklch(85% .105 62),oklch(20% .055 305));--color-surface:light-dark(oklch(98.5% .012 90),oklch(26.5% .065 305));--color-surface-sunken:light-dark(oklch(94.5% .03 80),oklch(22.5% .055 305));--color-surface-raised:light-dark(oklch(99% .01 90),oklch(30% .07 305));--color-surface-inverse:light-dark(oklch(25% .065 300),oklch(96% .02 90));--color-ink:light-dark(oklch(25% .065 300),oklch(97% .015 90));--color-ink-muted:light-dark(oklch(40% .055 300),oklch(84% .03 90));--color-ink-subtle:light-dark(oklch(45% .045 300),oklch(70% .04 300));--color-ink-inverse:light-dark(oklch(97% .015 90),oklch(25% .065 300));--color-line:light-dark(oklch(86% .03 70),oklch(36% .06 305));--color-line-strong:var(--color-ink);--section-divider-color:var(--color-ink);--control-checked-border:var(--color-ink);--marquee-edge:var(--color-ink);--color-accent:light-dark(oklch(66% .215 12),oklch(70% .2 12));--color-accent-hover:light-dark(oklch(70% .2 14),oklch(75% .19 14));--color-accent-ink:oklch(22% .065 300);--color-accent-text:light-dark(oklch(46.5% .19 12),oklch(78% .16 14));--color-accent-soft:light-dark(oklch(92% .06 15),oklch(36% .1 10));--color-highlight:light-dark(oklch(88% .165 92),oklch(86% .16 92));--color-highlight-ink:oklch(22% .065 300);--highlight-tone-positive-text:oklch(42% .09 190);--highlight-tone-caution-text:oklch(44% .1 75);--highlight-tone-critical-text:oklch(45% .19 25);--highlight-tone-info-text:oklch(43% .12 245);--highlight-accent-text:oklch(45% .19 12);--color-focus:var(--color-ink);--color-selection:light-dark(oklch(88% .165 92),oklch(55% .15 12));--color-scrim:light-dark(oklch(25% .065 300/.5),oklch(8% .04 305/.7));--tone-positive:light-dark(oklch(72% .12 185),oklch(76% .12 185));--tone-positive-soft:light-dark(oklch(92% .05 185),oklch(34% .06 190));--tone-positive-text:light-dark(oklch(43% .09 190),oklch(82% .1 185));--tone-positive-ink:oklch(22% .065 300);--tone-caution:light-dark(oklch(88% .165 92),oklch(86% .16 92));--tone-caution-soft:light-dark(oklch(95% .08 95),oklch(36% .07 90));--tone-caution-text:light-dark(oklch(45% .1 75),oklch(88% .14 92));--tone-caution-ink:oklch(22% .065 300);--tone-critical:light-dark(oklch(58% .22 25),oklch(66% .21 25));--tone-critical-soft:light-dark(oklch(92% .05 25),oklch(36% .1 25));--tone-critical-text:light-dark(oklch(46.5% .19 25),oklch(80% .14 22));--tone-critical-ink:light-dark(oklch(98.5% .01 25),oklch(18% .04 25));--tone-info:light-dark(oklch(62% .12 240),oklch(74% .11 238));--tone-info-soft:light-dark(oklch(92% .04 240),oklch(34% .07 245));--tone-info-text:light-dark(oklch(44.5% .12 245),oklch(82% .09 238));--tone-info-ink:oklch(22% .065 300);--color-cat-1:oklch(72% .19 12);--color-cat-2:oklch(86% .16 92);--color-cat-3:oklch(76% .12 185);--color-cat-4:oklch(76% .15 55);--color-cat-5:oklch(78% .11 240);--color-cat-6:oklch(80% .15 135);--color-cat-7:oklch(76% .12 330);--color-cat-8:oklch(82% .06 70);--color-cat-ink:oklch(22% .065 300);--shadow-surface:4px 4px 0 0 light-dark(oklch(25% .065 300),oklch(8% .04 305));--active-shift:2px;--shadow-active:2px 2px 0 0 light-dark(oklch(25% .065 300),oklch(8% .04 305));--shadow-float:5px 5px 0 0 light-dark(oklch(25% .065 300),oklch(8% .04 305));--shadow-overlay:8px 8px 0 0 light-dark(oklch(25% .065 300),oklch(8% .04 305));--canvas-image:radial-gradient(circle at 1px 1px, light-dark(oklch(25% .065 300/.07),oklch(97% .015 90/.05)) 1px, transparent 1.4px);--canvas-image-size:7px 7px}}@font-face{font-family:Big Shoulders;font-style:normal;font-display:swap;font-weight:100 900;src:url(../assets/fonts/big-shoulders-latin-ext-standard-normal.woff2)format("woff2-variations");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Big Shoulders;font-style:normal;font-display:swap;font-weight:100 900;src:url(../assets/fonts/big-shoulders-latin-standard-normal.woff2)format("woff2-variations");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Bricolage Grotesque;font-style:normal;font-display:swap;font-weight:200 800;font-stretch:75% 100%;src:url(../assets/fonts/bricolage-grotesque-latin-ext-standard-normal.woff2)format("woff2-variations");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Bricolage Grotesque;font-style:normal;font-display:swap;font-weight:200 800;font-stretch:75% 100%;src:url(../assets/fonts/bricolage-grotesque-latin-standard-normal.woff2)format("woff2-variations");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Martian Mono;font-style:normal;font-display:swap;font-weight:100 800;font-stretch:75% 112.5%;src:url(../assets/fonts/martian-mono-latin-ext-standard-normal.woff2)format("woff2-variations");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Martian Mono;font-style:normal;font-display:swap;font-weight:100 800;font-stretch:75% 112.5%;src:url(../assets/fonts/martian-mono-latin-standard-normal.woff2)format("woff2-variations");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
1
+ @layer kiln.reset,kiln.tokens;@layer kiln.themes{[data-theme=fiesta]{--font-display:"Big Shoulders", "Arial Narrow", ui-sans-serif, sans-serif;--font-text:"Bricolage Grotesque", ui-sans-serif, system-ui, sans-serif;--font-prose:"Bricolage Grotesque", ui-sans-serif, system-ui, sans-serif;--font-mono:"Martian Mono", ui-monospace, Menlo, monospace;--font-numeric:"Big Shoulders", "Arial Narrow", ui-sans-serif, sans-serif;--type-base:1rem;--display-scale:1;--type-ratio:1.28;--display-weight:850;--display-style:normal;--display-stretch:100%;--display-transform:uppercase;--display-tracking:.005em;--display-opsz:72;--heading-font:var(--font-display);--heading-weight:800;--heading-tracking:.01em;--heading-transform:uppercase;--label-weight:650;--label-tracking:0;--label-transform:none;--numeric-stretch:100%;--numeral-weight:600;--numeral-scale:1.12;--mono-stretch:75%;--table-head-font:var(--font-display);--leading-tight:.9;--leading-snug:1.1;--leading-body:1.5;--prose-size:1.0625rem;--prose-leading:1.55;--density:.92;--motion-scale:.9;--ease-out:cubic-bezier(.22, 1, .36, 1);--ease-in-out:cubic-bezier(.65, 0, .35, 1);--ease-spring:cubic-bezier(.34, 1.56, .64, 1);--icon-stroke:2.25;--border-width:2px;--border-width-strong:3px;--radius-action:999px;--radius-field:.75rem;--radius-surface:1.125rem;--radius-media:.75rem;--radius-chip:999px;--radius-avatar:50%;--color-canvas:light-dark(oklch(85% .105 62),oklch(20% .055 305));--color-surface:light-dark(oklch(98.5% .012 90),oklch(26.5% .065 305));--color-surface-sunken:light-dark(oklch(94.5% .03 80),oklch(22.5% .055 305));--color-surface-raised:light-dark(oklch(99% .01 90),oklch(30% .07 305));--color-surface-inverse:light-dark(oklch(25% .065 300),oklch(96% .02 90));--color-ink:light-dark(oklch(25% .065 300),oklch(97% .015 90));--color-ink-muted:light-dark(oklch(40% .055 300),oklch(84% .03 90));--color-ink-subtle:light-dark(oklch(45% .045 300),oklch(70% .04 300));--color-ink-inverse:light-dark(oklch(97% .015 90),oklch(25% .065 300));--color-line:light-dark(oklch(86% .03 70),oklch(36% .06 305));--color-line-strong:var(--color-ink);--section-divider-color:var(--color-ink);--control-checked-border:var(--color-ink);--marquee-edge:var(--color-ink);--color-accent:light-dark(oklch(66% .215 12),oklch(70% .2 12));--color-accent-hover:light-dark(oklch(70% .2 14),oklch(75% .19 14));--color-accent-ink:oklch(22% .065 300);--color-accent-text:light-dark(oklch(46.5% .19 12),oklch(78% .16 14));--color-accent-soft:light-dark(oklch(92% .06 15),oklch(36% .1 10));--color-highlight:light-dark(oklch(88% .165 92),oklch(86% .16 92));--color-highlight-ink:oklch(22% .065 300);--highlight-tone-positive-text:oklch(42% .09 190);--highlight-tone-caution-text:oklch(44% .1 75);--highlight-tone-critical-text:oklch(40% .15 28);--highlight-tone-info-text:oklch(43% .12 245);--highlight-accent-text:oklch(45% .19 12);--color-focus:var(--color-ink);--color-selection:light-dark(oklch(88% .165 92),oklch(55% .15 12));--color-scrim:light-dark(oklch(25% .065 300/.5),oklch(8% .04 305/.7));--tone-positive:light-dark(oklch(72% .12 185),oklch(76% .12 185));--tone-positive-soft:light-dark(oklch(92% .05 185),oklch(34% .06 190));--tone-positive-text:light-dark(oklch(43% .09 190),oklch(82% .1 185));--tone-positive-ink:oklch(22% .065 300);--tone-caution:light-dark(oklch(79% .155 68),oklch(78% .15 68));--tone-caution-soft:light-dark(oklch(93% .06 72),oklch(36% .07 70));--tone-caution-text:light-dark(oklch(45% .1 75),oklch(85% .13 75));--tone-caution-ink:oklch(22% .065 300);--tone-critical:light-dark(oklch(50% .19 28),oklch(62% .2 30));--tone-critical-soft:light-dark(oklch(92% .05 28),oklch(34% .09 28));--tone-critical-text:light-dark(oklch(40% .15 28),oklch(80% .13 32));--tone-critical-ink:light-dark(oklch(98.5% .01 25),oklch(18% .04 25));--tone-info:light-dark(oklch(62% .12 240),oklch(74% .11 238));--tone-info-soft:light-dark(oklch(92% .04 240),oklch(34% .07 245));--tone-info-text:light-dark(oklch(44.5% .12 245),oklch(82% .09 238));--tone-info-ink:oklch(22% .065 300);--color-cat-1:oklch(72% .19 12);--color-cat-2:oklch(80% .1 300);--color-cat-3:oklch(76% .12 185);--color-cat-4:oklch(72% .16 42);--color-cat-5:oklch(78% .11 240);--color-cat-6:oklch(80% .15 135);--color-cat-7:oklch(76% .12 330);--color-cat-8:oklch(82% .06 70);--color-cat-ink:oklch(22% .065 300);--shadow-surface:4px 4px 0 0 light-dark(oklch(25% .065 300),oklch(8% .04 305));--active-shift:2px;--shadow-active:2px 2px 0 0 light-dark(oklch(25% .065 300),oklch(8% .04 305));--shadow-float:5px 5px 0 0 light-dark(oklch(25% .065 300),oklch(8% .04 305));--shadow-overlay:8px 8px 0 0 light-dark(oklch(25% .065 300),oklch(8% .04 305));--canvas-image:radial-gradient(circle at 1px 1px, light-dark(oklch(25% .065 300/.07),oklch(97% .015 90/.05)) 1px, transparent 1.4px);--canvas-image-size:7px 7px}}@font-face{font-family:Big Shoulders;font-style:normal;font-display:swap;font-weight:100 900;src:url(../assets/fonts/big-shoulders-latin-ext-standard-normal.woff2)format("woff2-variations");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Big Shoulders;font-style:normal;font-display:swap;font-weight:100 900;src:url(../assets/fonts/big-shoulders-latin-standard-normal.woff2)format("woff2-variations");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Bricolage Grotesque;font-style:normal;font-display:swap;font-weight:200 800;font-stretch:75% 100%;src:url(../assets/fonts/bricolage-grotesque-latin-ext-standard-normal.woff2)format("woff2-variations");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Bricolage Grotesque;font-style:normal;font-display:swap;font-weight:200 800;font-stretch:75% 100%;src:url(../assets/fonts/bricolage-grotesque-latin-standard-normal.woff2)format("woff2-variations");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Martian Mono;font-style:normal;font-display:swap;font-weight:100 800;font-stretch:75% 112.5%;src:url(../assets/fonts/martian-mono-latin-ext-standard-normal.woff2)format("woff2-variations");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Martian Mono;font-style:normal;font-display:swap;font-weight:100 800;font-stretch:75% 112.5%;src:url(../assets/fonts/martian-mono-latin-standard-normal.woff2)format("woff2-variations");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@@ -10,6 +10,8 @@ export declare const space: (s: Space) => string;
10
10
  export type Tone = 'neutral' | 'accent' | 'positive' | 'caution' | 'critical' | 'info';
11
11
  /** Control sizes shared by Button, inputs, Tag, etc. */
12
12
  export type Size = 'sm' | 'md' | 'lg';
13
+ /** A categorical colour slot → `--color-cat-N`: a person, team or topic, matching its `Tag` and `Avatar`. */
14
+ export type CategoryColor = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
13
15
  /** Content widths for Container and prose measure. */
14
16
  export type Width = 'narrow' | 'text' | 'content' | 'wide' | 'full';
15
17
  export type Align = 'start' | 'center' | 'end' | 'stretch' | 'baseline';
@@ -1 +1 @@
1
- {"version":3,"file":"tokens.js","names":["space","s","alignCss","a","justifyCss","j"],"sources":["../../src/utils/tokens.ts"],"sourcesContent":["/**\n * Typed handles on the token scales. Components accept these unions as props and map\n * them to CSS variables — consumers never pass raw px, hex or ms values.\n */\n\n/** Spacing steps. Map to `var(--space-N)`; the actual size is theme-controlled (density). */\nexport const SPACE = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] as const\nexport type Space = (typeof SPACE)[number]\nexport const space = (s: Space): string => (s === 0 ? '0' : `var(--space-${String(s)})`)\n\n/** Semantic surface / tone names shared by colored components. */\nexport type Tone = 'neutral' | 'accent' | 'positive' | 'caution' | 'critical' | 'info'\n\n/** Control sizes shared by Button, inputs, Tag, etc. */\nexport type Size = 'sm' | 'md' | 'lg'\n\n/** Content widths for Container and prose measure. */\nexport type Width = 'narrow' | 'text' | 'content' | 'wide' | 'full'\n\nexport type Align = 'start' | 'center' | 'end' | 'stretch' | 'baseline'\nexport type Justify = 'start' | 'center' | 'end' | 'between' | 'around' | 'evenly'\n\nexport const alignCss = (a: Align): string =>\n a === 'start' ? 'flex-start' : a === 'end' ? 'flex-end' : a\n\nexport const justifyCss = (j: Justify): string =>\n j === 'start'\n ? 'flex-start'\n : j === 'end'\n ? 'flex-end'\n : j === 'between'\n ? 'space-between'\n : j === 'around'\n ? 'space-around'\n : j === 'evenly'\n ? 'space-evenly'\n : j\n"],"mappings":";AAQA,IAAaA,KAAS,MAAsBC,MAAM,IAAI,MAAM,eAAe,OAAOA,CAAC,EAAE,IAcxEC,KAAY,MACvBC,MAAM,UAAU,eAAeA,MAAM,QAAQ,aAAaA,GAE/CC,KAAc,MACzBC,MAAM,UACF,eACAA,MAAM,QACJ,aACAA,MAAM,YACJ,kBACAA,MAAM,WACJ,iBACAA,MAAM,WACJ,iBACAA"}
1
+ {"version":3,"file":"tokens.js","names":["space","s","alignCss","a","justifyCss","j"],"sources":["../../src/utils/tokens.ts"],"sourcesContent":["/**\n * Typed handles on the token scales. Components accept these unions as props and map\n * them to CSS variables — consumers never pass raw px, hex or ms values.\n */\n\n/** Spacing steps. Map to `var(--space-N)`; the actual size is theme-controlled (density). */\nexport const SPACE = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] as const\nexport type Space = (typeof SPACE)[number]\nexport const space = (s: Space): string => (s === 0 ? '0' : `var(--space-${String(s)})`)\n\n/** Semantic surface / tone names shared by colored components. */\nexport type Tone = 'neutral' | 'accent' | 'positive' | 'caution' | 'critical' | 'info'\n\n/** Control sizes shared by Button, inputs, Tag, etc. */\nexport type Size = 'sm' | 'md' | 'lg'\n\n/** A categorical colour slot → `--color-cat-N`: a person, team or topic, matching its `Tag` and `Avatar`. */\nexport type CategoryColor = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8\n\n/** Content widths for Container and prose measure. */\nexport type Width = 'narrow' | 'text' | 'content' | 'wide' | 'full'\n\nexport type Align = 'start' | 'center' | 'end' | 'stretch' | 'baseline'\nexport type Justify = 'start' | 'center' | 'end' | 'between' | 'around' | 'evenly'\n\nexport const alignCss = (a: Align): string =>\n a === 'start' ? 'flex-start' : a === 'end' ? 'flex-end' : a\n\nexport const justifyCss = (j: Justify): string =>\n j === 'start'\n ? 'flex-start'\n : j === 'end'\n ? 'flex-end'\n : j === 'between'\n ? 'space-between'\n : j === 'around'\n ? 'space-around'\n : j === 'evenly'\n ? 'space-evenly'\n : j\n"],"mappings":";AAQA,IAAaA,KAAS,MAAsBC,MAAM,IAAI,MAAM,eAAe,OAAOA,CAAC,EAAE,IAiBxEC,KAAY,MACvBC,MAAM,UAAU,eAAeA,MAAM,QAAQ,aAAaA,GAE/CC,KAAc,MACzBC,MAAM,UACF,eACAA,MAAM,QACJ,aACAA,MAAM,YACJ,kBACAA,MAAM,WACJ,iBACAA,MAAM,WACJ,iBACAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mitcsutt/kiln-ui",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "Kiln: a themeable React design system on Radix primitives, plain CSS and design tokens",
5
5
  "keywords": [
6
6
  "kiln",
@@ -57,7 +57,7 @@
57
57
  "devDependencies": {
58
58
  "@arethetypeswrong/cli": "^0.18.5",
59
59
  "@mitcsutt/kiln-testing-react18": "0.0.0",
60
- "@mitcsutt/kiln-tsconfig": "0.1.0",
60
+ "@mitcsutt/kiln-tsconfig": "0.2.0",
61
61
  "@tanstack/intent": "^0.5.3",
62
62
  "@storybook/react-vite": "^10.6.1",
63
63
  "@testing-library/jest-dom": "^7.0.1",
@@ -57,7 +57,7 @@ Strong themes take one idea from their subject and apply it everywhere, with eve
57
57
 
58
58
  If a choice can't be justified by the idea, leave it at the default. Write the one-line reason for each choice next to its value, and if you can't, change the choice. Pick at most two families and one accent.
59
59
 
60
- Generated UI also converges on a second set of looks: a cream canvas with a terracotta accent, near-black with one acid accent, a mint canvas with forest green, hard-offset shadows on every card, and a short list of "distinctive" fonts. Kiln's newer themes (Paper, Ledger, Flightdeck and Riso) avoid all of them. Monograph and Fiesta predate these rules and are kept unchanged for compatibility, so don't take them as a model. Kiln's [DESIGN.md](https://github.com/mitcsutt/kiln/blob/main/DESIGN.md) lists them in full.
60
+ Generated UI also converges on a second set of looks: a cream canvas with a terracotta accent, near-black with one acid accent, a mint canvas with forest green, hard-offset shadows on every card, and a short list of "distinctive" fonts. Kiln's newer themes (Paper, Ledger, Flightdeck and Riso) avoid all of them. Monograph and Fiesta predate these rules and keep their original design for compatibility, so don't take them as a model. Kiln's [DESIGN.md](https://github.com/mitcsutt/kiln/blob/main/DESIGN.md) lists them in full.
61
61
 
62
62
  ## 2. Copy the starter file
63
63
 
@@ -20,7 +20,7 @@ These rules come from [DESIGN.md](https://github.com/mitcsutt/kiln/blob/main/DES
20
20
  ## Principles
21
21
 
22
22
  1. **Themes are data, components are structure.** A component never knows which theme it is in. Everything visual is a token; a new theme is one CSS file and zero component changes.
23
- 2. **One idea per theme, drawn from its subject.** Paper is an office that prints for everyone, on grey recycled stock in blue-black ink. Monograph is a scholar's monograph read under a desk lamp. Ledger is an accountant's columnar pad. Fiesta is a screen-printed festival poster. Flightdeck is a glass-cockpit display. Riso is a two-drum risograph zine. Monograph and Fiesta predate the second-order rules in §2 and are kept unchanged for compatibility. Every choice in a theme designed since has a one-line reason traced to its subject, written in the stylesheet next to the value. If you can't write the reason, the choice is wrong and it doesn't ship.
23
+ 2. **One idea per theme, drawn from its subject.** Paper is an office that prints for everyone, on grey recycled stock in blue-black ink. Monograph is a scholar's monograph read under a desk lamp. Ledger is an accountant's columnar pad. Fiesta is a screen-printed festival poster. Flightdeck is a glass-cockpit display. Riso is a two-drum risograph zine. Monograph and Fiesta predate the second-order rules in §2 and keep their original design for compatibility (Fiesta's status and categorical inks have since been tuned apart for real use). Every choice in a theme designed since has a one-line reason traced to its subject, written in the stylesheet next to the value. If you can't write the reason, the choice is wrong and it doesn't ship.
24
24
  3. **Props, not styles.** Consumers compose layout and intent through typed props (`gap={5}`, `tone="critical"`, `width="text"`). No utility classes, no inline style soup, no raw px/hex/ms at call sites. `className` exists as an escape hatch, not a workflow.
25
25
  4. **Durable by default.** Every component forwards refs, spreads native props, works with React 18 and 19, is keyboard- and screen-reader-complete, respects `prefers-reduced-motion`, and renders on the server.
26
26
  5. **Specific beats safe.** The median choice is the wrong choice (see [Not AI slop](#not-ai-slop)).
@@ -41,6 +41,7 @@ Generated UI converges on the statistical median: indigo buttons, Inter, gradien
41
41
  - **Two families max per theme** (+ a mono for code/figures where the theme needs it), clearly distinct, one with real character.
42
42
  - **Big contrast**: the largest display step is ≥ 5× body. Display tracking tightens with size (−0.02 to −0.04em); line-height drops to ~0.9–1.05.
43
43
  - **`tabular-nums` on every number that aligns or updates**: counts, money, tables, dates. `<Numeral>`/`<Amount>` do this for you.
44
+ - **Navigation text stays off the caption steps.** Links, nav items and tabs are read and scanned like body copy: `NavLinks` is `--text-md` (`sm`: `--text-sm`), and no navigation label uses `--text-xs` or `--text-2xs`. Those steps are for captions, badges, keyboard hints and metadata. A label that must stay compact, like `BottomNav`'s under its icon, floors at `0.75rem`. The `Usage` stories of `NavLinks`, `Tabs` and `BottomNav` enforce this in the browser (`pnpm test:storybook`), checking each label's computed size in the current theme.
44
45
  - Prose measure ≤ 70ch (`width="text"`). `text-wrap: balance` on headings, `pretty` on paragraphs (the reset does it).
45
46
  - **Banned patterns:** accenting one word of a headline in italic/colour; a tracked ALL-CAPS eyebrow over every section; `01 / 02 / 03` numbering on things that aren't a sequence; monospace used as decoration for small labels.
46
47
 
@@ -66,7 +67,7 @@ Models that are told to avoid the tells above converge on a second set instead (
66
67
 
67
68
  The rest is review.
68
69
 
69
- **Legacy exemption.** Monograph and Fiesta are listed as `LEGACY` in that test and are exempt, along with the font stylesheets only they use (`fonts-monograph.css`, `fonts-fiesta.css` and `fonts-martian-mono.css`), because they ship unchanged from before these rules ([ADR 0030](https://github.com/mitcsutt/kiln/blob/main/docs/adr/0030-theme-family-without-ai-tells.md)). Monograph still has its ember accent and serif display, and Fiesta its apricot canvas and halftone. Do not treat them as precedent: a new theme gets no exemption, and a redesigned Monograph or Fiesta loses its own.
70
+ **Legacy exemption.** Monograph and Fiesta are listed as `LEGACY` in that test and are exempt, along with the font stylesheets only they use (`fonts-monograph.css`, `fonts-fiesta.css` and `fonts-martian-mono.css`), because they keep their design from before these rules ([ADR 0030](https://github.com/mitcsutt/kiln/blob/main/docs/adr/0030-theme-family-without-ai-tells.md)). Monograph still has its ember accent and serif display, and Fiesta its apricot canvas and halftone. Do not treat them as precedent: a new theme gets no exemption, and a redesigned Monograph or Fiesta loses its own.
70
71
 
71
72
  The banned font families, from the research: the first-order defaults plus the faces models now reach for as "distinctive" escapes (several are on Anthropic's own recommended list): Inter, Roboto, Open Sans, Poppins, Montserrat, Space Grotesk, Space Mono, Geist, DM Sans, DM Serif, Manrope, Plus Jakarta Sans, Outfit, Sora, Syne, Satoshi, Cabinet Grotesk, Clash Display, General Sans, Instrument Sans, Instrument Serif, Fraunces, Playfair Display, Cormorant, Lora, EB Garamond, Newsreader, Bricolage Grotesque, IBM Plex, JetBrains Mono and Fira Code. The list goes stale as model defaults move: change the list in the test and here together.
72
73
 
@@ -78,20 +79,23 @@ Beyond the checks, a theme has a subject, and each colour, face, radius and easi
78
79
  - **Asymmetric splits** (`<Split ratio="5/7">`), a hang column for labels, at least one element per page that breaks the column.
79
80
  - **Vary section rhythm.** The space scale is non-linear (4 8 12 16 24 32 48 64 96 144…) and adjacent `<Section>`s should not use the same `space`.
80
81
  - **Not everything is a card.** Prefer lists, tables, rules and whitespace. A card needs a reason: it's interactive, draggable, or a self-contained object.
82
+ - **A list on a busy canvas gets one sheet, not a card per row.** Where rows would float on a textured or coloured canvas, `List` and `Table` take `surface` (`surface` or `raised`): the whole list sits on one sheet and its rows, fills, rails and rules stay rows inside it.
81
83
  - The hero is the subject's most characteristic thing: the open invoices, the release board, today's orders. Not a stat row with a gradient.
82
84
 
83
85
  ### Components & depth
84
86
 
85
87
  - **Radii are roles**, not a global roundness: `--radius-action`, `--radius-field`, `--radius-surface`, `--radius-media`, `--radius-chip`, `--radius-avatar`. Nested radii shrink (inner = outer − padding).
86
88
  - **One edge treatment per element**: a border _or_ a shadow _or_ a fill change. Static structure uses hairlines; soft shadows are only for things that float (popover, menu, dialog). Hard-offset shadows never go on static surfaces in a new theme. Fiesta keeps its hard offset as a legacy preset: it is the print misregistration, and it _is_ the edge. Riso's misregistered offset (the second ink drum slightly off) is floating-only.
87
- - **Icons**: the library ships ~20 glyphs on a 20px grid with a themed stroke. At most one icon per row; never an icon in a tinted chip; never emoji as UI.
89
+ - **Icons**: the library ships ~40 glyphs on a 20px grid with a themed stroke: the ones its components need, plus common navigation and page-furniture glyphs so apps don't mix in a second set. At most one icon per row; never an icon in a tinted chip; never emoji as UI.
88
90
  - **No left-border-accent callouts.** Alerts are a neutral hairline frame; the tone lives only in the glyph and a short tab on the top edge (`variant="soft"` for a tinted box when it must shout).
89
- - **Empty states** mark their frame with printer's crop marks, not a dashed box.
91
+ - **Categorical colour marks who, never how.** A row or card with `color` draws a thin rail or a top keyline in `--color-cat-N`, matching that person's or team's `Tag` and `Avatar`. It's identity, not status or emphasis, so it's not the accent callout above; tones stay in badges and figures.
92
+ - **Empty states** mark their frame with printer's crop marks, not a dashed box. So does a placeholder `Card`, a slot not yet decided.
90
93
  - **Focus is neutral** (`--color-focus` = ink) and always visible on `:focus-visible`. Focus must never look like validation; only error/warning/success tint a field.
91
94
 
92
95
  ### Motion
93
96
 
94
97
  - Motion answers an action or shows a state change (count updated, row expanded, panel opened). **No fade-up-on-scroll, no hover-scale on static cards, no parallax.**
98
+ - To point at something that just changed or that a link just opened on, wrap it in `Flash`: one primitive for any element, not a flash prop on each component. It's an outline that fades, so it never moves layout, and under reduced motion it holds and goes instead of fading.
95
99
  - Durations and easings are tokens (`--dur-1/2/3`, `--ease-out`, `--ease-spring`) and collapse to ~0 under `prefers-reduced-motion`.
96
100
 
97
101
  ### Copy (for stories, docs and examples)
@@ -18,6 +18,7 @@ sources:
18
18
  - mitcsutt/kiln:packages/ui/src/components/layout/ActionBar/ActionBar.tsx
19
19
  - mitcsutt/kiln:packages/ui/src/components/layout/Divider/Divider.tsx
20
20
  - mitcsutt/kiln:packages/ui/src/components/layout/AspectRatio/AspectRatio.tsx
21
+ - mitcsutt/kiln:packages/ui/src/components/layout/ScrollArea/ScrollArea.tsx
21
22
  - mitcsutt/kiln:packages/ui/src/components/layout/VisuallyHidden/VisuallyHidden.tsx
22
23
  - mitcsutt/kiln:apps/docs/content/docs/ui/patterns/dashboard.mdx
23
24
  - mitcsutt/kiln:apps/docs/content/docs/ui/patterns/settings.mdx
@@ -431,6 +432,7 @@ Read a reference when its description matches the task:
431
432
  - [ActionBar](references/action-bar.md): The row of actions at the end of a form or dialog. Cancel, save, continue.
432
433
  - [Divider](references/divider.md): A hairline rule between groups of content, optionally labelled, horizontal or vertical.
433
434
  - [AspectRatio](references/aspect-ratio.md): A frame that keeps its proportions, for images, video, maps and charts.
435
+ - [ScrollArea](references/scroll-area.md): A scroll container for content wider or taller than the page, such as a bracket, a timeline or a wide board, that keyboard users can reach and scroll.
434
436
  - [VisuallyHidden](references/visually-hidden.md): Content that screen readers announce and sighted readers don't need to see.
435
437
  - [Dashboard](references/dashboard.md): A week of operations at a glance, built from stats, a table and a list. No tiles, no gradients, no cards that don't need to be cards.
436
438
  - [Settings](references/settings.md): A settings page with section navigation, labelled fields, grouped switches and a guarded destructive action.
@@ -92,7 +92,7 @@ export function Usage() {
92
92
 
93
93
  `AppShell.Header`, `AppShell.Sidebar`, `AppShell.Main`, `AppShell.Footer` and `AppShell.BottomBar` place themselves, so their order in JSX doesn't affect the layout. Keep it the same as the reading order anyway: header, sidebar, main, footer, bottom bar.
94
94
 
95
- - **Header** is sticky by default (`sticky={false}` to scroll it away). Put a `Container` and an `Inline` inside.
95
+ - **Header** is sticky by default (`sticky={false}` to scroll it away). While it sticks, in-page links and `scrollIntoView` land just below it, whatever its height. Put a `Container` and an `Inline` inside.
96
96
  - **Sidebar** appears from `navBreakpoint` up. It sits at the start of the main region (`side="end"` for the other side), scrolls on its own, and stays below the header.
97
97
  - **Main** is the `<main>` landmark and the skip link's target.
98
98
  - **BottomBar** is pinned to the bottom of the viewport below `navBreakpoint`, and pads for the phone's home indicator.
@@ -117,7 +117,7 @@ Also accepts every prop of `HTMLAttributes<HTMLDivElement>`.
117
117
 
118
118
  | Prop | Type | Default | Description |
119
119
  | --- | --- | --- | --- |
120
- | `sticky` | `boolean` | `true` | Stick to the top of the viewport while scrolling. Default `true`. |
120
+ | `sticky` | `boolean` | `true` | Stick to the top of the viewport while scrolling. Default `true`. While it sticks, in-page links and `scrollIntoView` land below it, however tall it grows. |
121
121
 
122
122
  Also accepts every prop of `HTMLAttributes<HTMLElement>`.
123
123
 
@@ -30,6 +30,25 @@ export function Usage() {
30
30
  }
31
31
  ```
32
32
 
33
+ ## Accent panel
34
+
35
+ `surface="accent"` is a rounded panel in the accent colour, for the one thing on a page that should shout. Text, links and buttons inside it take the accent's own ink.
36
+
37
+ ```tsx
38
+ import { Box, Stack, Text } from '@mitcsutt/kiln-ui'
39
+
40
+ export function AccentPanel() {
41
+ return (
42
+ <Box surface="accent" padding={5} radius="surface">
43
+ <Stack gap={2}>
44
+ <Text weight="medium">Ferry tickets go on sale Monday at 09:00</Text>
45
+ <Text size="sm">Weekend crossings sell out within the hour, so set a reminder.</Text>
46
+ </Stack>
47
+ </Box>
48
+ )
49
+ }
50
+ ```
51
+
33
52
  ## API
34
53
 
35
54
  `BoxProps`:
@@ -39,7 +58,8 @@ export function Usage() {
39
58
  | `padding` | `Responsive<Space>` | | Padding on every side. Responsive. |
40
59
  | `paddingX` | `Responsive<Space>` | | Inline (left/right) padding; overrides `padding` on that axis. Responsive. |
41
60
  | `paddingY` | `Responsive<Space>` | | Block (top/bottom) padding; overrides `padding` on that axis. Responsive. |
42
- | `surface` | `'none' \| 'surface' \| 'canvas' \| 'sunken' \| 'raised' \| 'inverse'` | `none` | Background fill. `inverse` also re-points ink and line colours for its children. |
61
+ | `surface` | `'none' \| 'accent' \| 'surface' \| 'canvas' \| 'sunken' \| 'raised' \| 'inverse' \| 'cat-6' \| 'cat-3' \| 'cat-5' \| 'cat-1' \| 'cat-2' \| 'cat-4' \| 'cat-7' \| 'cat-8'` | `none` | Background fill. `inverse`, `accent` and the categorical `cat-1` to `cat-8` (one person's or team's colour, matching their `Tag`) also re-point ink, line and accent colours for its children, so they stay legible on the fill. |
62
+ | `adaptTones` | `boolean` | `false` | On an `inverse`, `accent` or categorical fill, re-point the status tones too, so tone text and soft tone fills (a `Stat` delta, a toned `Numeral` or `Text`, a soft `Badge`) stay AA on the fill. On `accent` and categorical fills tone text becomes the fill's ink, so the sign, glyph or label carries the status; on `inverse` each tone keeps its hue. Off by default, so tones keep the page's colours. No effect on other surfaces. |
43
63
  | `border` | `boolean` | `false` | Hairline border in `--color-line`. One edge treatment per element — a border *or* a fill. |
44
64
  | `radius` | `'none' \| 'surface' \| 'field' \| 'media'` | `none` | Corner radius, by role. |
45
65
  | `as` | `'div' \| 'section' \| 'article' \| 'aside' \| 'header' \| 'footer' \| 'li' \| 'span'` | `div` | |
@@ -8,6 +8,8 @@ Source: https://kiln.mitchellsutton.com/docs/ui/layout/divider
8
8
 
9
9
  `Divider` separates groups. For a rule between every item of a list, use `Stack dividers` instead, which spaces the rules for you.
10
10
 
11
+ A labelled divider is a band rather than a separator: its label is content that screen readers read in place, and the rules either side of it are decorative.
12
+
11
13
  A labelled divider names the group that follows. `spacing` adds space above and below from the space scale, `strong` uses the stronger line colour, and `decorative` hides the rule from assistive technology when it carries no meaning (it's a `separator` otherwise).
12
14
 
13
15
  ```tsx
@@ -32,6 +34,33 @@ export function Usage() {
32
34
  }
33
35
  ```
34
36
 
37
+ ## Block label
38
+
39
+ A label can be a block: a few lines set into the rule, like a verdict and a time between two halves of a timetable. It's read in place as ordinary content.
40
+
41
+ ```tsx
42
+ import { Divider, Stack, Text } from '@mitcsutt/kiln-ui'
43
+
44
+ export function BlockLabel() {
45
+ return (
46
+ <Divider
47
+ labelPosition="center"
48
+ spacing={4}
49
+ label={
50
+ <Stack gap={1} align="center">
51
+ <Text size="sm" weight="strong">
52
+ Change at Harbour Square
53
+ </Text>
54
+ <Text size="sm" tone="muted">
55
+ Connection 6 minutes
56
+ </Text>
57
+ </Stack>
58
+ }
59
+ />
60
+ )
61
+ }
62
+ ```
63
+
35
64
  ## API
36
65
 
37
66
  `DividerProps`:
@@ -40,7 +69,7 @@ export function Usage() {
40
69
  | --- | --- | --- | --- |
41
70
  | `orientation` | `'horizontal' \| 'vertical'` | `horizontal` | Default `horizontal`. A vertical rule stretches to its flex/grid row. |
42
71
  | `strong` | `boolean` | `false` | Heavier rule in `--color-line-strong` at `--border-width-strong`. |
43
- | `label` | `ReactNode` | | Text set into a horizontal rule, e.g. "Earlier this week". It also names the separator. |
72
+ | `label` | `ReactNode` | | Content set into a horizontal rule, e.g. "Earlier this week". It's real content, read like any text, and may be a block (a `Stack` of lines); the rules either side are decorative. |
44
73
  | `labelPosition` | `'start' \| 'center'` | `start` | Where the label sits. Default `start` (left-aligned by default); `center` for a lone break. |
45
74
  | `spacing` | `0 \| 1 \| 2 \| 3 \| 4 \| 5 \| 6 \| 7 \| 8 \| 9 \| 10 \| 11 \| 12` | | Margin on both sides of the rule (block axis if horizontal, inline if vertical). |
46
75
  | `decorative` | `boolean` | `false` | Purely visual: hide it from assistive tech. Use when the rule only repeats a boundary that headings or landmarks already convey. |
@@ -0,0 +1,68 @@
1
+ <!-- Generated from the Kiln docs by apps/docs/src/skills. Edit the docs pages, then run `pnpm generate:skills`. -->
2
+
3
+ # ScrollArea
4
+
5
+ > A scroll container for content wider or taller than the page, such as a bracket, a timeline or a wide board, that keyboard users can reach and scroll.
6
+
7
+ Source: https://kiln.mitchellsutton.com/docs/ui/layout/scroll-area
8
+
9
+ `ScrollArea` lets one wide thing scroll on its own instead of pushing the page sideways. Give it a `label` and it's a named region in the tab order, so someone without a mouse or touch screen can focus it and scroll with the arrow keys. The scrollbar takes the theme's line colour.
10
+
11
+ A data table doesn't need one: `Table` scrolls sideways itself, and takes the same `label`.
12
+
13
+ Something wider than the page, such as a knockout bracket, scrolls inside a `ScrollArea` instead of pushing the page sideways. Its `label` makes it a named region that keyboard users can focus and scroll with the arrow keys.
14
+
15
+ ```tsx
16
+ import { Badge, Card, Inline, ScrollArea, Stack, Text } from '@mitcsutt/kiln-ui'
17
+
18
+ const ROUNDS = [
19
+ { round: 'Round of 16', ties: ['Kelso Bay 2–1 Old Quay', 'Harbour Square 0–0 Marram Point'] },
20
+ { round: 'Quarter-finals', ties: ['Kelso Bay 3–2 North Point', 'Harbour Square 1–0 Eastgate'] },
21
+ { round: 'Semi-finals', ties: ['Kelso Bay 1–1 Harbour Square'] },
22
+ { round: 'Final', ties: ['Saturday 14:00 at Harbour Park'] },
23
+ ]
24
+
25
+ export function Usage() {
26
+ return (
27
+ <ScrollArea label="Knockout rounds">
28
+ <Inline gap={4} wrap={false}>
29
+ {ROUNDS.map((r) => (
30
+ <Card key={r.round}>
31
+ <Card.Body>
32
+ <Stack gap={2} align="start">
33
+ <Text weight="medium">{r.round}</Text>
34
+ {r.ties.map((tie) => (
35
+ <Badge key={tie} variant="outline">
36
+ {tie}
37
+ </Badge>
38
+ ))}
39
+ </Stack>
40
+ </Card.Body>
41
+ </Card>
42
+ ))}
43
+ </Inline>
44
+ </ScrollArea>
45
+ )
46
+ }
47
+ ```
48
+
49
+ ## API
50
+
51
+ `ScrollAreaProps`:
52
+
53
+ | Prop | Type | Default | Description |
54
+ | --- | --- | --- | --- |
55
+ | `label` | `string` | | Names the area. With a name (this, or `aria-labelledby`) it becomes a labelled region that keyboard users can focus and scroll with the arrow keys. |
56
+ | `axis` | `'both' \| 'x' \| 'y'` | `x` | Which way it scrolls. On `x` and `both` the content keeps its natural width, so a row of cards scrolls instead of squeezing. `y` and `both` scroll once a parent gives the area a height (a grid row, a pane). Default `x`. |
57
+ | `hideBelow` | `'sm' \| 'md' \| 'lg' \| 'xl'` | | Hide below this breakpoint (e.g. `md` → hidden on phones, shown from 48em). |
58
+ | `hideAbove` | `'sm' \| 'md' \| 'lg' \| 'xl'` | | Hide from this breakpoint up (e.g. `md` → shown on phones only). |
59
+
60
+ Also accepts every prop of `HTMLAttributes<HTMLDivElement>`.
61
+
62
+ ### Component tokens
63
+
64
+ Set these in a theme, or on one element, to change this component without touching the rest.
65
+
66
+ | Token | Default and use |
67
+ | --- | --- |
68
+ | `--scroll-area-thumb` | default var(--color-line-strong) — the scrollbar's thumb |
@@ -39,9 +39,30 @@ export function Usage() {
39
39
  }
40
40
  ```
41
41
 
42
+ ## Categorical band
43
+
44
+ `surface="cat-1"` to `"cat-8"` paints a band in a categorical colour, one person's or team's colour, matching their `Tag`. Ink and lines flip to stay legible on it.
45
+
46
+ ```tsx
47
+ import { Container, Heading, Section, Stack, Text } from '@mitcsutt/kiln-ui'
48
+
49
+ export function CategoricalBand() {
50
+ return (
51
+ <Section surface="cat-2" space={6}>
52
+ <Container>
53
+ <Stack gap={2}>
54
+ <Heading level={2}>Ada's crew</Heading>
55
+ <Text tone="muted">Three boats, eleven crossings this week.</Text>
56
+ </Stack>
57
+ </Container>
58
+ </Section>
59
+ )
60
+ }
61
+ ```
62
+
42
63
  ## Surfaces and bands
43
64
 
44
- `surface` is `canvas`, `surface`, `sunken`, `inverse` or `accent`. On `inverse` and `accent`, the colour roles flip for everything inside, so text, links, focus rings and buttons stay legible with no extra props. `divider` adds a rule at the `top`, `bottom` or `both`.
65
+ `surface` is `canvas`, `surface`, `sunken`, `inverse`, `accent`, or a categorical `cat-1` to `cat-8` (a band in one person's or team's colour, matching their `Tag`). On `inverse`, `accent` and the categorical bands, the colour roles flip for everything inside, so text, links, focus rings and buttons stay legible with no extra props. Add `adaptTones` to flip the status tones too. `divider` adds a rule at the `top`, `bottom` or `both`.
45
66
 
46
67
  ## API
47
68
 
@@ -50,7 +71,8 @@ export function Usage() {
50
71
  | Prop | Type | Default | Description |
51
72
  | --- | --- | --- | --- |
52
73
  | `space` | `Responsive<Space>` | `8` | Block padding (top and bottom), as a step on the space scale. Responsive. Vary it: adjacent sections should not share the same step. Default `8`. |
53
- | `surface` | `'accent' \| 'surface' \| 'canvas' \| 'sunken' \| 'inverse'` | | Full-bleed band colour. Omit to stay transparent on the canvas. `inverse` and `accent` re-point the ink, line and focus colours so children stay legible. |
74
+ | `surface` | `'accent' \| 'surface' \| 'canvas' \| 'sunken' \| 'inverse' \| 'cat-6' \| 'cat-3' \| 'cat-5' \| 'cat-1' \| 'cat-2' \| 'cat-4' \| 'cat-7' \| 'cat-8'` | | Full-bleed band colour. Omit to stay transparent on the canvas. `inverse`, `accent` and the categorical `cat-1` to `cat-8` re-point the ink, line and focus colours so children stay legible. |
75
+ | `adaptTones` | `boolean` | `false` | On an `inverse`, `accent` or categorical band, re-point the status tones too, so tone text and soft tone fills (a `Stat` delta, a toned `Numeral` or `Text`, a soft `Badge`) stay AA on the band. On `accent` and categorical bands tone text becomes the band's ink, so the sign, glyph or label carries the status; on `inverse` each tone keeps its hue. Off by default, so tones keep the page's colours. No effect on other surfaces. |
54
76
  | `divider` | `'top' \| 'bottom' \| 'both'` | | A hairline across the full bleed at the top, bottom or both edges. |
55
77
  | `as` | `'div' \| 'section' \| 'article' \| 'aside' \| 'header' \| 'footer'` | `section` | |
56
78
  | `hideBelow` | `'sm' \| 'md' \| 'lg' \| 'xl'` | | Hide below this breakpoint (e.g. `md` → hidden on phones, shown from 48em). |
@@ -128,11 +128,11 @@ export default function RootLayout({ children }: { children: React.ReactNode })
128
128
  The reader's mode is stored in `localStorage` under `kiln-color-mode`. Every app on one origin shares that key, so a choice made in one carries into the next. Give each app its own key with `storageKey`, or keep a key the app already used so returning readers keep their choice. Pass the same key to `themeScript`:
129
129
 
130
130
  ```tsx
131
- ;<ThemeProvider theme="ledger" defaultMode="light" storageKey="budget:color-mode">
131
+ ;<ThemeProvider theme="ledger" defaultMode="light" storageKey="acme:color-mode">
132
132
  …
133
133
  </ThemeProvider>
134
134
 
135
- themeScript('ledger', 'light', { storageKey: 'budget:color-mode' })
135
+ themeScript('ledger', 'light', { storageKey: 'acme:color-mode' })
136
136
  ```
137
137
 
138
138
  ### Without server rendering
@@ -152,7 +152,7 @@ export default defineConfig({
152
152
  transformIndexHtml: () => [
153
153
  {
154
154
  tag: 'script',
155
- children: themeScript('ledger', 'light', { storageKey: 'budget:color-mode' }),
155
+ children: themeScript('ledger', 'light', { storageKey: 'acme:color-mode' }),
156
156
  injectTo: 'head-prepend',
157
157
  },
158
158
  ],
@@ -8,7 +8,7 @@ Source: https://kiln.mitchellsutton.com/docs/ui/themes/fiesta
8
8
 
9
9
  _A screen-printed festival poster and sticker album._ Screen printing can't do gradients, so neither does Fiesta: flat spot inks on apricot poster stock, everything keylined in aubergine, and a hard misregistered offset where other themes have a soft shadow.
10
10
 
11
- Fiesta predates Kiln's [second-order design rules](https://kiln.mitchellsutton.com/docs/ui/foundations/design-rules#second-order-tells) and ships unchanged for compatibility, so it isn't the model for a new theme.
11
+ Fiesta predates Kiln's [second-order design rules](https://kiln.mitchellsutton.com/docs/ui/foundations/design-rules#second-order-tells) and keeps its original design for compatibility, so it isn't the model for a new theme. Its status inks are kept apart for real use: the gold is only the highlight ("you"), caution is marigold, and critical is a deep brick that never reads as the coral accent.
12
12
 
13
13
 
14
14
  ## Use it