@adnap/krysalicss 0.0.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.
Files changed (172) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +119 -0
  3. package/dist/base/global.css +141 -0
  4. package/dist/base/global.min.css +1 -0
  5. package/dist/base/reset.css +170 -0
  6. package/dist/base/reset.min.css +1 -0
  7. package/dist/element/badge.css +167 -0
  8. package/dist/element/badge.min.css +1 -0
  9. package/dist/element/button.css +250 -0
  10. package/dist/element/button.min.css +1 -0
  11. package/dist/element/checkbox.css +149 -0
  12. package/dist/element/checkbox.min.css +1 -0
  13. package/dist/element/file.css +148 -0
  14. package/dist/element/file.min.css +1 -0
  15. package/dist/element/progress.css +183 -0
  16. package/dist/element/progress.min.css +1 -0
  17. package/dist/element/radio.css +144 -0
  18. package/dist/element/radio.min.css +1 -0
  19. package/dist/element/range.css +183 -0
  20. package/dist/element/range.min.css +1 -0
  21. package/dist/element/select.css +156 -0
  22. package/dist/element/select.min.css +1 -0
  23. package/dist/element/switch.css +186 -0
  24. package/dist/element/switch.min.css +1 -0
  25. package/dist/element/text-input.css +143 -0
  26. package/dist/element/text-input.min.css +1 -0
  27. package/dist/element/textarea.css +145 -0
  28. package/dist/element/textarea.min.css +1 -0
  29. package/dist/helper/breakpoints.css +113 -0
  30. package/dist/helper/breakpoints.min.css +1 -0
  31. package/dist/helper/state.css +126 -0
  32. package/dist/helper/state.min.css +1 -0
  33. package/dist/krysalicss.css +1420 -0
  34. package/dist/krysalicss.css.map +1 -0
  35. package/dist/krysalicss.min.css +1 -0
  36. package/dist/layout/container.css +145 -0
  37. package/dist/layout/container.min.css +1 -0
  38. package/dist/layout/flex.css +135 -0
  39. package/dist/layout/flex.min.css +1 -0
  40. package/dist/layout/grid.css +188 -0
  41. package/dist/layout/grid.min.css +1 -0
  42. package/dist/module/alert.css +166 -0
  43. package/dist/module/alert.min.css +1 -0
  44. package/dist/module/card.css +157 -0
  45. package/dist/module/card.min.css +1 -0
  46. package/dist/module/field.css +138 -0
  47. package/dist/module/field.min.css +1 -0
  48. package/dist/module/modal.css +187 -0
  49. package/dist/module/modal.min.css +1 -0
  50. package/dist/module/navbar.css +256 -0
  51. package/dist/module/navbar.min.css +1 -0
  52. package/dist/module/tabs.css +167 -0
  53. package/dist/module/tabs.min.css +1 -0
  54. package/dist/tokens/dark.json +85 -0
  55. package/dist/tokens/default.json +85 -0
  56. package/dist/tokens/high-contrast.json +85 -0
  57. package/dist/typography/base.css +131 -0
  58. package/dist/typography/base.min.css +1 -0
  59. package/dist/typography/content.css +137 -0
  60. package/dist/typography/content.min.css +1 -0
  61. package/dist/typography/link.css +132 -0
  62. package/dist/typography/link.min.css +1 -0
  63. package/dist/typography/table.css +121 -0
  64. package/dist/typography/table.min.css +1 -0
  65. package/dist/typography/title.css +122 -0
  66. package/dist/typography/title.min.css +1 -0
  67. package/package.json +111 -0
  68. package/src/_index.scss +18 -0
  69. package/src/base/_index.scss +2 -0
  70. package/src/base/global/_index.scss +2 -0
  71. package/src/base/global/_plugin.scss +34 -0
  72. package/src/base/global/_variables.scss +11 -0
  73. package/src/base/reset/_index.scss +2 -0
  74. package/src/base/reset/_plugin.scss +70 -0
  75. package/src/base/reset/_variables.scss +5 -0
  76. package/src/element/_index.scss +11 -0
  77. package/src/element/badge/_index.scss +2 -0
  78. package/src/element/badge/_plugin.scss +44 -0
  79. package/src/element/badge/_variables.scss +19 -0
  80. package/src/element/button/_index.scss +2 -0
  81. package/src/element/button/_plugin.scss +173 -0
  82. package/src/element/button/_variables.scss +36 -0
  83. package/src/element/checkbox/_index.scss +2 -0
  84. package/src/element/checkbox/_plugin.scss +48 -0
  85. package/src/element/checkbox/_variables.scss +24 -0
  86. package/src/element/file/_index.scss +2 -0
  87. package/src/element/file/_plugin.scss +45 -0
  88. package/src/element/file/_variables.scss +27 -0
  89. package/src/element/progress/_index.scss +2 -0
  90. package/src/element/progress/_plugin.scss +96 -0
  91. package/src/element/progress/_variables.scss +19 -0
  92. package/src/element/radio/_index.scss +2 -0
  93. package/src/element/radio/_plugin.scss +47 -0
  94. package/src/element/radio/_variables.scss +16 -0
  95. package/src/element/range/_index.scss +2 -0
  96. package/src/element/range/_plugin.scss +101 -0
  97. package/src/element/range/_variables.scss +19 -0
  98. package/src/element/select/_index.scss +2 -0
  99. package/src/element/select/_plugin.scss +58 -0
  100. package/src/element/select/_variables.scss +26 -0
  101. package/src/element/switch/_index.scss +2 -0
  102. package/src/element/switch/_plugin.scss +105 -0
  103. package/src/element/switch/_variables.scss +28 -0
  104. package/src/element/text-input/_index.scss +2 -0
  105. package/src/element/text-input/_plugin.scss +37 -0
  106. package/src/element/text-input/_variables.scss +22 -0
  107. package/src/element/textarea/_index.scss +2 -0
  108. package/src/element/textarea/_plugin.scss +39 -0
  109. package/src/element/textarea/_variables.scss +22 -0
  110. package/src/helper/_breakpoints.scss +45 -0
  111. package/src/helper/_controls.scss +82 -0
  112. package/src/helper/_index.scss +3 -0
  113. package/src/helper/_state.scss +35 -0
  114. package/src/krysalicss.scss +17 -0
  115. package/src/layout/_index.scss +3 -0
  116. package/src/layout/container/_index.scss +2 -0
  117. package/src/layout/container/_plugin.scss +26 -0
  118. package/src/layout/container/_variables.scss +5 -0
  119. package/src/layout/flex/_index.scss +2 -0
  120. package/src/layout/flex/_plugin.scss +32 -0
  121. package/src/layout/flex/_variables.scss +9 -0
  122. package/src/layout/grid/_index.scss +2 -0
  123. package/src/layout/grid/_plugin.scss +37 -0
  124. package/src/layout/grid/_variables.scss +37 -0
  125. package/src/module/_index.scss +6 -0
  126. package/src/module/alert/_index.scss +2 -0
  127. package/src/module/alert/_plugin.scss +51 -0
  128. package/src/module/alert/_variables.scss +24 -0
  129. package/src/module/card/_index.scss +2 -0
  130. package/src/module/card/_plugin.scss +31 -0
  131. package/src/module/card/_variables.scss +13 -0
  132. package/src/module/field/_index.scss +2 -0
  133. package/src/module/field/_plugin.scss +49 -0
  134. package/src/module/field/_variables.scss +26 -0
  135. package/src/module/modal/_index.scss +2 -0
  136. package/src/module/modal/_plugin.scss +137 -0
  137. package/src/module/modal/_variables.scss +39 -0
  138. package/src/module/navbar/_index.scss +2 -0
  139. package/src/module/navbar/_plugin.scss +186 -0
  140. package/src/module/navbar/_variables.scss +49 -0
  141. package/src/module/tabs/_index.scss +2 -0
  142. package/src/module/tabs/_plugin.scss +106 -0
  143. package/src/module/tabs/_variables.scss +16 -0
  144. package/src/theme/_create.scss +74 -0
  145. package/src/theme/dark.scss +51 -0
  146. package/src/theme/default.scss +45 -0
  147. package/src/theme/high-contrast.scss +53 -0
  148. package/src/typography/_index.scss +5 -0
  149. package/src/typography/base/_index.scss +2 -0
  150. package/src/typography/base/_plugin.scss +21 -0
  151. package/src/typography/base/_variables.scss +15 -0
  152. package/src/typography/content/_index.scss +2 -0
  153. package/src/typography/content/_plugin.scss +39 -0
  154. package/src/typography/content/_variables.scss +1 -0
  155. package/src/typography/link/_index.scss +2 -0
  156. package/src/typography/link/_mixins.scss +29 -0
  157. package/src/typography/link/_plugin.scss +15 -0
  158. package/src/typography/link/_variables.scss +15 -0
  159. package/src/typography/table/_index.scss +2 -0
  160. package/src/typography/table/_plugin.scss +13 -0
  161. package/src/typography/table/_variables.scss +6 -0
  162. package/src/typography/title/_index.scss +2 -0
  163. package/src/typography/title/_plugin.scss +36 -0
  164. package/src/typography/title/_variables.scss +7 -0
  165. package/src/variables/_color.scss +66 -0
  166. package/src/variables/_default.scss +52 -0
  167. package/src/variables/_feature.scss +39 -0
  168. package/src/variables/_global.scss +93 -0
  169. package/src/variables/_index.scss +7 -0
  170. package/src/variables/_responsive.scss +10 -0
  171. package/src/variables/_selector.scss +1 -0
  172. package/src/variables/_size.scss +5 -0
@@ -0,0 +1,22 @@
1
+ @use "../../variables";
2
+
3
+ // Covers every text-flavoured native input. Listed individually rather than via
4
+ // `input:not([type])` because the latter also matches non-text types (number is
5
+ // a text-like control, but checkbox/radio/etc. need different rules and are
6
+ // handled by their own plugins). Order is alphabetical for deterministic
7
+ // selector list output.
8
+ $selector: 'input[type="email"], input[type="number"], input[type="password"], input[type="search"], input[type="tel"], input[type="text"], input[type="url"]'
9
+ !default;
10
+
11
+ $padding-y: variables.$size-extra-small !default;
12
+ $padding-x: variables.$size-small !default;
13
+
14
+ $border-radius: variables.$global-border-radius !default;
15
+ $border-width: variables.$global-border-width !default;
16
+
17
+ $focus-outline-width: variables.$global-focus-outline-width !default;
18
+ $focus-outline-style: variables.$global-focus-outline-style !default;
19
+ $focus-outline-offset: variables.$global-focus-outline-offset !default;
20
+
21
+ $disabled-opacity: variables.$global-disabled-opacity !default;
22
+ $border-mix: variables.$global-border-mix !default;
@@ -0,0 +1,2 @@
1
+ @forward "variables";
2
+ @forward "plugin";
@@ -0,0 +1,39 @@
1
+ @use "variables" as *;
2
+ @use "../../variables";
3
+ @use "../../helper/controls" as controls;
4
+
5
+ @if variables.$feature-element-textarea {
6
+ #{$selector} {
7
+ @include variables.backgroundColor(input-bg, transparent);
8
+ @include variables.textColor(input-fg, currentColor);
9
+ display: block;
10
+ width: 100%;
11
+ min-height: $min-height;
12
+ padding: $padding-y $padding-x;
13
+ @include controls.borderWithMix($border-width, $border-mix);
14
+ border-radius: $border-radius;
15
+ font: inherit;
16
+ line-height: 1.4;
17
+ resize: $resize;
18
+
19
+ &:focus-visible {
20
+ @include controls.focus-ring(
21
+ $focus-outline-width,
22
+ $focus-outline-style,
23
+ $focus-outline-offset,
24
+ );
25
+ border-color: var(--kc-fg, currentColor);
26
+ }
27
+
28
+ @include controls.invalidControl();
29
+
30
+ &:disabled {
31
+ @include controls.disabledControl($disabled-opacity);
32
+ }
33
+
34
+ &::placeholder {
35
+ color: color-mix(in srgb, currentColor 65%, transparent);
36
+ opacity: 1;
37
+ }
38
+ }
39
+ }
@@ -0,0 +1,22 @@
1
+ @use "../../variables";
2
+
3
+ $selector: "textarea" !default;
4
+
5
+ $padding-y: variables.$size-extra-small !default;
6
+ $padding-x: variables.$size-small !default;
7
+
8
+ $border-radius: variables.$global-border-radius !default;
9
+ $border-width: variables.$global-border-width !default;
10
+
11
+ $focus-outline-width: variables.$global-focus-outline-width !default;
12
+ $focus-outline-style: variables.$global-focus-outline-style !default;
13
+ $focus-outline-offset: variables.$global-focus-outline-offset !default;
14
+
15
+ $disabled-opacity: variables.$global-disabled-opacity !default;
16
+ $border-mix: variables.$global-border-mix !default;
17
+
18
+ $min-height: 4rem !default;
19
+
20
+ // Vertical-only resize is the safer default: horizontal resize on a fluid
21
+ // container can break responsive layouts. Consumers can override to `both`.
22
+ $resize: vertical !default;
@@ -0,0 +1,45 @@
1
+ @use "sass:map";
2
+ @use "../variables";
3
+
4
+ // Viewport-query mixins. `$device` is a key from `$responsive-breakpoints`
5
+ // (`tablet`, `desktop`, `widescreen`, `fullhd`); `mobile` is `null` and
6
+ // not valid here.
7
+ @mixin from($device) {
8
+ @media screen and (min-width: map.get(
9
+ variables.$responsive-breakpoints,
10
+ $device
11
+ )) {
12
+ @content;
13
+ }
14
+ }
15
+
16
+ @mixin until($device) {
17
+ @media screen and (max-width: map.get(
18
+ variables.$responsive-breakpoints,
19
+ $device
20
+ )
21
+ - 1px) {
22
+ @content;
23
+ }
24
+ }
25
+
26
+ // Container-query counterparts. Same `$responsive-breakpoints` keyspace;
27
+ // resolves against the nearest containment context rather than the
28
+ // viewport. Caller is responsible for declaring `container-type` (and
29
+ // optionally `container-name`) on the host element. Most module
30
+ // variables expose a `$container-name` opt-in for that.
31
+ @mixin containerFrom($device) {
32
+ @container (min-width: #{map.get(
33
+ variables.$responsive-breakpoints,
34
+ $device
35
+ )}) {
36
+ @content;
37
+ }
38
+ }
39
+
40
+ @mixin containerUntil($device) {
41
+ @container (max-width: #{map.get(variables.$responsive-breakpoints, $device)
42
+ - 1px}) {
43
+ @content;
44
+ }
45
+ }
@@ -0,0 +1,82 @@
1
+ @use "sass:list";
2
+ @use "../variables";
3
+
4
+ // Shared affordances for interactive controls (form inputs, buttons, tabs,
5
+ // links, navbar items). Each form-control plugin used to inline these four
6
+ // blocks verbatim; centralising them here keeps the focus / disabled /
7
+ // invalid / border-mix contracts in one place and lets the framework
8
+ // version focus behaviour globally (fall-back chains, double rings, etc.)
9
+ // without touching every component.
10
+
11
+ // `$token` defaults to the global `focus-ring` token; the fallback chain
12
+ // keeps the outline visible in themes that haven't shipped a focus-ring
13
+ // override (falls through to `--kc-fg` and then `currentColor`). Plugins
14
+ // that want a different focus token (rare) pass `$token: <name>`.
15
+ @mixin focus-ring(
16
+ $width: variables.$global-focus-outline-width,
17
+ $style: variables.$global-focus-outline-style,
18
+ $offset: variables.$global-focus-outline-offset,
19
+ $token: focus-ring,
20
+ ) {
21
+ outline: $width $style var(--kc-#{$token}, var(--kc-fg, currentColor));
22
+ outline-offset: $offset;
23
+ }
24
+
25
+ @mixin disabledControl($opacity: variables.$global-disabled-opacity) {
26
+ cursor: not-allowed;
27
+ opacity: $opacity;
28
+ }
29
+
30
+ // Form-control border tint. The control inherits `color` from the surface
31
+ // so mixing `currentColor` with transparent keeps the border tuned against
32
+ // the foreground regardless of theme. WCAG 1.4.11 (3:1 non-text contrast)
33
+ // is held by `$global-border-mix` (50%).
34
+ @mixin borderWithMix(
35
+ $width: variables.$global-border-width,
36
+ $mix: variables.$global-border-mix,
37
+ $color: currentColor,
38
+ ) {
39
+ border: $width solid color-mix(in srgb, $color #{$mix}, transparent);
40
+ }
41
+
42
+ // `:user-invalid` (not `:invalid`): only flags after interaction or submit
43
+ // attempt, avoiding the false-positive red ring on untouched `required`
44
+ // fields. `[aria-invalid="true"]` remains the manual hook for JS-validated
45
+ // forms. `$color-token` lets a caller redirect the cue (rare).
46
+ @mixin invalidControl($color-token: danger-bg) {
47
+ &:user-invalid,
48
+ &[aria-invalid="true"] {
49
+ border-color: var(--kc-#{$color-token}, currentColor);
50
+ }
51
+ }
52
+
53
+ // Nested-link affordance for surface modules (alert, card). The page-level
54
+ // `--kc-link` is calibrated against the page bg, not the module surface bg;
55
+ // pinning links to `currentColor` keeps them paired with the surface fg
56
+ // (contrast-safe by construction on themed `.is-*` variants). Underline
57
+ // preserves the link cue now that colour alone can't (WCAG 1.4.1).
58
+ @mixin nestedLinks {
59
+ a {
60
+ color: currentColor;
61
+ text-decoration: underline;
62
+ }
63
+ }
64
+
65
+ // Iterate over the framework's colour combinations and emit a per-label
66
+ // child selector that assigns `--kc-<prefix><label>-bg` / `-fg` tokens.
67
+ // Components whose `using ($label, $tuple)` body is JUST these two calls
68
+ // (alert, card) replace the inline block with a single
69
+ // `@include controls.combinations-apply()`. Components with additional
70
+ // per-combination rules (button) keep the inline block.
71
+ @mixin combinations-apply($bg-token-prefix: "", $fg-token-prefix: "") {
72
+ @include variables.combinations using ($label, $tuple) {
73
+ @include variables.backgroundColor(
74
+ "#{$bg-token-prefix}#{$label}-bg",
75
+ list.nth($tuple, 1),
76
+ );
77
+ @include variables.textColor(
78
+ "#{$fg-token-prefix}#{$label}-fg",
79
+ list.nth($tuple, 2),
80
+ );
81
+ }
82
+ }
@@ -0,0 +1,3 @@
1
+ @forward "breakpoints";
2
+ @forward "controls";
3
+ @forward "state" as state-*;
@@ -0,0 +1,35 @@
1
+ @use "sass:map";
2
+ @use "../variables";
3
+
4
+ // `[data-state]` icon hook. Pairs with the `.is-<label>` colour combinations
5
+ // to satisfy WCAG 1.4.1 (Use of Colour): a non-colour cue precedes the label
6
+ // so colour-blind users, monochrome displays, and forced-colours mode all
7
+ // read the state. Consumers opt their markup in:
8
+ //
9
+ // <span data-state="success">Saved</span>
10
+ //
11
+ // Defaults are baked in as the `var()` fallback per label; consumers who set
12
+ // `--kc-state-icon-<label>` at any scope override the glyph (or `''` to drop
13
+ // it).
14
+ //
15
+ // Only labels with a non-empty glyph emit a rule: the `default`, `light`,
16
+ // and `primary` combinations have no inherent state semantic, so emitting an
17
+ // empty `::before` for them is pure dead weight. Consumers who want to opt
18
+ // those in can add `$icons` keys via `@use 'helper/state' with (...)`.
19
+ $selector-attr: "data-state" !default;
20
+
21
+ // Trailing space is U+0020 so the icon visually separates from the label
22
+ // without an extra wrapping element.
23
+ $icons: (
24
+ success: "✓ ",
25
+ warning: "⚠ ",
26
+ danger: "✕ ",
27
+ ) !default;
28
+
29
+ @if variables.$feature-helper-state {
30
+ @each $label, $glyph in $icons {
31
+ [#{$selector-attr}="#{$label}"]::before {
32
+ content: var(--kc-state-icon-#{$label}, "#{$glyph}");
33
+ }
34
+ }
35
+ }
@@ -0,0 +1,17 @@
1
+ // Batteries-included entry. Pulls every category, the default
2
+ // light theme, and the dark theme (auto-switching via prefers-color-scheme +
3
+ // opt-in `.theme-dark` override). Consumers wanting only one theme should
4
+ // use `_index.scss` and import their chosen theme(s) themselves.
5
+ //
6
+ // Re-export the feature-flag list under `$feature-list` so consumers can
7
+ // tree-shake from the root entry:
8
+ // @use '@adnap/krysalicss' with ($feature-list: ('base-reset', 'element-button'));
9
+ // `_feature.scss` already declares `$list: true !default;`, so a bare
10
+ // @forward keeps the variable configurable downstream without locking the
11
+ // value via a redundant `with` clause (which would error if the module had
12
+ // been loaded transitively first via a per-component `_variables.scss`).
13
+ @forward "variables/feature" as feature-*;
14
+
15
+ @use "theme/default";
16
+ @use "theme/dark";
17
+ @use "index";
@@ -0,0 +1,3 @@
1
+ @forward "container" as container-*;
2
+ @forward "flex" as flex-*;
3
+ @forward "grid" as grid-*;
@@ -0,0 +1,2 @@
1
+ @forward "variables";
2
+ @forward "plugin";
@@ -0,0 +1,26 @@
1
+ @use "variables" as *;
2
+ @use "../../variables";
3
+ @use "../../helper/breakpoints" as breakpoints;
4
+
5
+ @if variables.$feature-layout-container {
6
+ #{$selector} {
7
+ flex-grow: 1;
8
+ margin: 0 auto;
9
+ position: relative;
10
+ width: auto;
11
+ padding-inline-start: $gutter;
12
+ padding-inline-end: $gutter;
13
+
14
+ @if $fluid-modifier {
15
+ @each $device, $size in variables.$responsive-breakpoints {
16
+ @include breakpoints.from($device) {
17
+ max-width: $size;
18
+ }
19
+ }
20
+
21
+ &#{variables.$selector-prefix-is}#{$fluid-modifier} {
22
+ max-width: none;
23
+ }
24
+ }
25
+ }
26
+ }
@@ -0,0 +1,5 @@
1
+ @use "../../variables";
2
+
3
+ $gutter: variables.$global-gap !default;
4
+ $selector: ".container" !default;
5
+ $fluid-modifier: "fluid" !default;
@@ -0,0 +1,2 @@
1
+ @forward "variables";
2
+ @forward "plugin";
@@ -0,0 +1,32 @@
1
+ @use "variables" as *;
2
+ @use "../../variables";
3
+
4
+ @if variables.$feature-layout-flex {
5
+ #{$flex-selector} {
6
+ display: flex;
7
+ flex-wrap: wrap;
8
+ gap: $gap;
9
+
10
+ &.no-wrap {
11
+ flex-wrap: nowrap;
12
+ }
13
+
14
+ &#{variables.$selector-prefix-is}centered {
15
+ justify-content: center;
16
+ }
17
+
18
+ &#{variables.$selector-prefix-is}vertical {
19
+ flex-direction: column;
20
+ }
21
+
22
+ > #{$column-selector} {
23
+ flex: 1 1 0;
24
+ min-width: 0;
25
+
26
+ // Sizes to its content instead of growing to share row width.
27
+ &#{$narrow-selector} {
28
+ flex: none;
29
+ }
30
+ }
31
+ }
32
+ }
@@ -0,0 +1,9 @@
1
+ @use "../../variables";
2
+
3
+ $flex-selector: ".flex" !default;
4
+ $column-selector: ".col" !default;
5
+ $narrow-selector: "#{variables.$selector-prefix-is}narrow" !default;
6
+
7
+ // Inter-item gap, applied via native CSS `gap` (Baseline since 2021).
8
+ // Defaults to the global token so flex and grid share spacing rhythm.
9
+ $gap: variables.$global-gap !default;
@@ -0,0 +1,2 @@
1
+ @forward "variables";
2
+ @forward "plugin";
@@ -0,0 +1,37 @@
1
+ @use "sass:map";
2
+ @use "variables" as *;
3
+ @use "../../variables";
4
+
5
+ @if variables.$feature-layout-grid {
6
+ #{$selector} {
7
+ display: grid;
8
+ gap: $gap;
9
+ // Default behaviour: responsive auto-fit. Cells stretch to fill the row
10
+ // and reflow into more / fewer columns as the viewport changes. No media
11
+ // queries required: the CSS Grid algorithm handles it.
12
+ grid-template-columns: repeat(auto-fit, minmax($auto-min, 1fr));
13
+
14
+ // Explicit column-count variants: `.grid.is-cols-3` etc.
15
+ @each $n in $column-modifiers {
16
+ &#{variables.$selector-prefix-is}cols-#{$n} {
17
+ grid-template-columns: repeat($n, minmax(0, 1fr));
18
+ }
19
+ }
20
+
21
+ // Cell spans. Apply to direct children with `.cell.is-span-N` or
22
+ // `.cell.is-half` etc. Cells with no span class fill one column.
23
+ > #{$cell-selector} {
24
+ @for $i from 1 through $columns {
25
+ &#{variables.$selector-prefix-is}span-#{$i} {
26
+ grid-column: span $i;
27
+ }
28
+ }
29
+
30
+ @each $label, $span in $named-spans {
31
+ &#{variables.$selector-prefix-is}#{$label} {
32
+ grid-column: span $span;
33
+ }
34
+ }
35
+ }
36
+ }
37
+ }
@@ -0,0 +1,37 @@
1
+ @use "../../variables";
2
+
3
+ // Container + cell selectors. Both configurable so consumers can rescope to a
4
+ // class prefix or web-component shadow root without forking the source.
5
+ $selector: ".grid" !default;
6
+ $cell-selector: ".cell" !default;
7
+
8
+ // `gap` between rows + columns. Uses CSS `gap` natively (unlike flex which
9
+ // pads columns then negative-margins the row), so no half-step math needed.
10
+ $gap: variables.$global-gap !default;
11
+
12
+ // Auto-fit min cell width. The default `.grid` container is responsive:
13
+ // `repeat(auto-fit, minmax($auto-min, 1fr))`. Cells flow into as many columns
14
+ // as fit at the current viewport width. Override via:
15
+ // @use '@adnap/krysalicss' with ($layout-grid-auto-min: 14rem);
16
+ $auto-min: 16rem !default;
17
+
18
+ // Total columns for the explicit-grid variant (`.grid.is-cols-N` and
19
+ // `.cell.is-span-N`). 12 mirrors the flex grid's division count so consumers
20
+ // can reuse the same mental model.
21
+ $columns: 12 !default;
22
+
23
+ // Explicit column-count modifiers emitted as `.grid.is-cols-<N>`. Listed
24
+ // values get `repeat(<N>, minmax(0, 1fr))`. Trim the list to ship a smaller
25
+ // CSS surface; the default covers the common-case grid widths.
26
+ $column-modifiers: (2, 3, 4, 6, 12) !default;
27
+
28
+ // Named cell spans: match the flex grid's `.col.is-half`, `.is-one-third`,
29
+ // etc. naming so the API feels consistent across both layouts.
30
+ $named-spans: (
31
+ full: 12,
32
+ half: 6,
33
+ one-third: 4,
34
+ two-thirds: 8,
35
+ one-quarter: 3,
36
+ three-quarters: 9,
37
+ ) !default;
@@ -0,0 +1,6 @@
1
+ @forward "card" as card-*;
2
+ @forward "alert" as alert-*;
3
+ @forward "field" as field-*;
4
+ @forward "navbar" as navbar-*;
5
+ @forward "modal" as modal-*;
6
+ @forward "tabs" as tabs-*;
@@ -0,0 +1,2 @@
1
+ @forward "variables";
2
+ @forward "plugin";
@@ -0,0 +1,51 @@
1
+ @use "sass:list";
2
+ @use "variables" as *;
3
+ @use "../../variables";
4
+ @use "../../helper/controls" as controls;
5
+
6
+ @if variables.$feature-module-alert {
7
+ #{$selector} {
8
+ @include variables.backgroundColor(
9
+ alert-bg,
10
+ list.nth($default-combination, 1),
11
+ );
12
+ @include variables.textColor(alert-fg, list.nth($default-combination, 2));
13
+ display: flex;
14
+ align-items: flex-start;
15
+ gap: $icon-gap;
16
+ padding: $padding-y $padding-x;
17
+ border-radius: $border-radius;
18
+ border-inline-start-width: $accent-width;
19
+ border-inline-start-style: solid;
20
+ border-inline-start-color: var(
21
+ --kc-fg,
22
+ #{list.nth($default-combination, 2)}
23
+ );
24
+
25
+ @if $container-name {
26
+ container-type: inline-size;
27
+ container-name: #{$container-name};
28
+ }
29
+
30
+ > #{$icon-selector} {
31
+ flex: 0 0 auto;
32
+ // Inherit the body line-height so the icon's first-line box matches
33
+ // the prose first-line box height. With `align-items: flex-start`
34
+ // above this means the glyph centres line up with the first line of
35
+ // text instead of floating above it. Pre-fix the icon used
36
+ // `line-height: 1` (~1em box) against ~1.5em text boxes, so the
37
+ // glyph rendered visibly higher than the text baseline.
38
+ line-height: inherit;
39
+ }
40
+
41
+ // Nested links inherit the surface fg + carry an underline. The
42
+ // page-level --kc-link is calibrated against page bg, not against
43
+ // alert surface bg; pairing the link with the alert's own fg colour
44
+ // is contrast-safe by construction (it's the same colour that the
45
+ // body text reads at). The underline preserves the link affordance
46
+ // now that colour alone can't (WCAG 1.4.1).
47
+ @include controls.nestedLinks;
48
+
49
+ @include controls.combinations-apply();
50
+ }
51
+ }
@@ -0,0 +1,24 @@
1
+ @use "../../variables";
2
+
3
+ $selector: ".alert" !default;
4
+ $icon-selector: ".alert__icon" !default;
5
+
6
+ $padding-y: variables.$size-small !default;
7
+ $padding-x: variables.$size-normal !default;
8
+
9
+ $border-radius: variables.$global-border-radius !default;
10
+
11
+ // Left-edge accent: 3px solid stripe in the page foreground (`--kc-fg`).
12
+ // Stays constant across combinations — only the background changes per
13
+ // combination, so the stripe reads as a fixed identity marker.
14
+ // Width chosen to read as a stripe rather than a border at default sizes.
15
+ $accent-width: 3px !default;
16
+
17
+ // Gap between an optional `.alert__icon` slot and the prose body. Consumers
18
+ // supply their own icon glyph; the framework only standardises spacing.
19
+ $icon-gap: variables.$size-extra-small !default;
20
+
21
+ $default-combination: variables.$color-combination-default !default;
22
+
23
+ // Opt-in container-query host. See `module/card/_variables.scss` for rationale.
24
+ $container-name: null !default;
@@ -0,0 +1,2 @@
1
+ @forward "variables";
2
+ @forward "plugin";
@@ -0,0 +1,31 @@
1
+ @use "sass:list";
2
+ @use "variables" as *;
3
+ @use "../../variables";
4
+ @use "../../helper/controls" as controls;
5
+
6
+ @if variables.$feature-module-card {
7
+ #{$selector} {
8
+ @include variables.backgroundColor(
9
+ card-bg,
10
+ list.nth($default-combination, 1),
11
+ );
12
+ @include variables.textColor(card-fg, list.nth($default-combination, 2));
13
+ padding: $gap;
14
+ border-radius: $border-radius;
15
+ border: 1px solid color-mix(in srgb, currentColor 12%, transparent);
16
+
17
+ @if $container-name {
18
+ container-type: inline-size;
19
+ container-name: #{$container-name};
20
+ }
21
+
22
+ // Nested links inherit the surface fg + carry an underline. Same
23
+ // rationale as alert: page-level --kc-link is calibrated against page
24
+ // bg, not card surface bg; pairing with the card's own fg avoids
25
+ // contrast failures on themed `.is-*` variants and on default cards
26
+ // in dark themes. Underline preserves the link cue (WCAG 1.4.1).
27
+ @include controls.nestedLinks;
28
+
29
+ @include controls.combinations-apply();
30
+ }
31
+ }
@@ -0,0 +1,13 @@
1
+ @use "../../variables";
2
+
3
+ $selector: ".card" !default;
4
+ $gap: variables.$global-gap !default;
5
+ $border-radius: variables.$global-border-radius !default;
6
+ $default-combination: variables.$color-combination-default !default;
7
+
8
+ // Opt-in container-query host. When non-null, the plugin emits
9
+ // `container-type: inline-size; container-name: <value>;` on the card so
10
+ // consumers can scope their own `containerFrom(...)` rules to card width
11
+ // instead of the viewport. The framework itself emits no container-query
12
+ // rules for card today; this is a hook for downstream code.
13
+ $container-name: null !default;
@@ -0,0 +1,2 @@
1
+ @forward "variables";
2
+ @forward "plugin";
@@ -0,0 +1,49 @@
1
+ @use "variables" as *;
2
+ @use "../../variables";
3
+
4
+ @if variables.$feature-module-field {
5
+ #{$selector} {
6
+ display: flex;
7
+ flex-direction: column;
8
+ gap: $gap;
9
+ margin-block-end: $margin-bottom;
10
+
11
+ > #{$label-selector} {
12
+ font-weight: 600;
13
+ }
14
+
15
+ > #{$help-selector} {
16
+ font-size: $help-font-size;
17
+ color: color-mix(in srgb, currentColor #{$help-mix}, transparent);
18
+ }
19
+
20
+ // `.field.is-invalid` lets consumers flag the whole field (label + help
21
+ // tinted danger) without reaching into individual control selectors.
22
+ // Uses `:where()`-style scoping via direct child to keep specificity low
23
+ // and avoid leaking into nested fields.
24
+ &#{$invalid-selector} > #{$help-selector} {
25
+ color: var(--kc-danger-bg, currentColor);
26
+ }
27
+
28
+ // Non-colour cue for invalid state. Triggered by the explicit
29
+ // `.is-invalid` modifier OR `:has(:user-invalid, [aria-invalid="true"])`.
30
+ // `:user-invalid` (not `:invalid`) avoids painting the glyph on every
31
+ // untouched `required` control: the user must have interacted (or
32
+ // attempted submit) before the danger cue fires. `:has()` and
33
+ // `:user-invalid` are both in our evergreen baseline. WCAG 1.4.1 + 1.4.11.
34
+ &#{$invalid-selector} > #{$label-selector}::before,
35
+ &:has(:user-invalid) > #{$label-selector}::before,
36
+ &:has([aria-invalid="true"]) > #{$label-selector}::before {
37
+ content: var(--kc-state-icon-danger, "#{$invalid-icon}");
38
+ color: var(--kc-danger-bg, currentColor);
39
+ }
40
+
41
+ // Disabled-field hint dims the label + help so the visual state matches
42
+ // the underlying control. The control itself dims via its own `:disabled`
43
+ // rule; this just keeps surrounding text in sync.
44
+ &#{$disabled-selector} > #{$label-selector},
45
+ &#{$disabled-selector} > #{$help-selector} {
46
+ opacity: 0.6;
47
+ }
48
+ }
49
+ }