@capra/core 1.12.0 → 1.13.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.
package/dist/style.css CHANGED
@@ -523,7 +523,7 @@
523
523
  color: var(--cds2-temporary-input-foreground-disabled);
524
524
  }
525
525
  }
526
- .capra-fieldLayout-module-GZD11W-field {
526
+ .capra-fieldLayout-module-0mM4jW-field {
527
527
  gap: var(--cds2-spacing-sm);
528
528
  flex-direction: column;
529
529
  width: 100%;
@@ -531,17 +531,17 @@
531
531
  display: flex;
532
532
 
533
533
  &[data-layout="horizontal"] {
534
- align-items: center;
534
+ align-items: flex-start;
535
535
  gap: var(--cds2-spacing-md);
536
536
  flex-direction: row;
537
537
 
538
- & .capra-fieldLayout-module-GZD11W-labelRow {
538
+ & .capra-fieldLayout-module-0mM4jW-labelRow {
539
539
  min-height: var(--cds2-dimension-component-md);
540
540
  flex-shrink: 0;
541
541
  align-items: center;
542
542
  }
543
543
 
544
- & .capra-fieldLayout-module-GZD11W-fieldContent {
544
+ & .capra-fieldLayout-module-0mM4jW-fieldContent {
545
545
  gap: var(--cds2-spacing-sm);
546
546
  flex-direction: column;
547
547
  flex: 1 1 0;
@@ -550,11 +550,11 @@
550
550
  }
551
551
  }
552
552
 
553
- & .capra-fieldLayout-module-GZD11W-fieldContent {
553
+ & .capra-fieldLayout-module-0mM4jW-fieldContent {
554
554
  display: contents;
555
555
  }
556
556
 
557
- & .capra-fieldLayout-module-GZD11W-labelRow {
557
+ & .capra-fieldLayout-module-0mM4jW-labelRow {
558
558
  align-items: center;
559
559
  gap: var(--cds2-spacing-xs);
560
560
  display: flex;
@@ -1046,7 +1046,7 @@ input:disabled + .capra-Radio-module-ZI7rzq-inner:after {
1046
1046
  border-color: var(--cds2-color-border-accent-strong);
1047
1047
  }
1048
1048
  }
1049
- .capra-Switch-module-16LYpW-switch {
1049
+ .capra-Switch-module-j8Yc-q-switch {
1050
1050
  --_cds-switch-height: var(--cds2-dimension-component-sm);
1051
1051
  --_cds-switch-width: var(--cds2-dimension-component-xl);
1052
1052
  --_cds-switch-handle-spacing: var(--cds2-spacing-xs);
@@ -1056,7 +1056,7 @@ input:disabled + .capra-Radio-module-ZI7rzq-inner:after {
1056
1056
  --_cds-switch-handle-horizontal-extension: calc(var(--_cds-switch-handle-size) * .3);
1057
1057
  -webkit-appearance: none;
1058
1058
  appearance: none;
1059
- background: var(--cds2-color-neutral-a4);
1059
+ background: var(--cds2-color-neutral-track);
1060
1060
  border-radius: var(--cds2-radius-full);
1061
1061
  box-sizing: border-box;
1062
1062
  cursor: pointer;
@@ -1069,25 +1069,30 @@ input:disabled + .capra-Radio-module-ZI7rzq-inner:after {
1069
1069
  overflow: visible;
1070
1070
  }
1071
1071
 
1072
- .capra-Switch-module-16LYpW-switch[data-size="sm"] {
1072
+ .capra-Switch-module-j8Yc-q-switch[data-size="sm"] {
1073
1073
  --_cds-switch-height: var(--cds2-dimension-component-xs);
1074
1074
  --_cds-switch-width: var(--cds2-dimension-component-md);
1075
1075
  }
1076
1076
 
1077
- .capra-Switch-module-16LYpW-switch[data-disabled="true"], .capra-Switch-module-16LYpW-switch:disabled {
1077
+ .capra-Switch-module-j8Yc-q-switch[data-disabled="true"], .capra-Switch-module-j8Yc-q-switch:disabled {
1078
+ background: var(--cds2-color-neutral-a4);
1078
1079
  cursor: not-allowed;
1079
1080
 
1081
+ &:checked {
1082
+ background: var(--cds2-color-accent-a4);
1083
+ }
1084
+
1080
1085
  &:before {
1081
1086
  background: var(--cds2-color-background-neutral-subtle);
1082
1087
  }
1083
1088
  }
1084
1089
 
1085
- .capra-Switch-module-16LYpW-switch:focus-visible {
1090
+ .capra-Switch-module-j8Yc-q-switch:focus-visible {
1086
1091
  outline: var(--cds2-border-focus);
1087
1092
  outline-offset: var(--cds2-spacing-xs);
1088
1093
  }
1089
1094
 
1090
- .capra-Switch-module-16LYpW-switch:before {
1095
+ .capra-Switch-module-j8Yc-q-switch:before {
1091
1096
  content: "";
1092
1097
  top: var(--_cds-switch-handle-spacing);
1093
1098
  width: var(--_cds-switch-handle-size);
@@ -1106,24 +1111,24 @@ input:disabled + .capra-Radio-module-ZI7rzq-inner:after {
1106
1111
  position: absolute;
1107
1112
  }
1108
1113
 
1109
- .capra-Switch-module-16LYpW-switch:checked:not(:disabled) {
1110
- background: var(--cds2-color-background-accent-indicator);
1114
+ .capra-Switch-module-j8Yc-q-switch:checked:not(:disabled) {
1115
+ background: var(--cds2-color-accent-track);
1111
1116
  }
1112
1117
 
1113
- .capra-Switch-module-16LYpW-switch:checked:before {
1118
+ .capra-Switch-module-j8Yc-q-switch:checked:before {
1114
1119
  left: var(--_cds-switch-handle-checked-left);
1115
1120
  }
1116
1121
 
1117
- .capra-Switch-module-16LYpW-switch:not(:disabled):active:before {
1122
+ .capra-Switch-module-j8Yc-q-switch:not(:disabled):active:before {
1118
1123
  width: calc(var(--_cds-switch-handle-size) + var(--_cds-switch-handle-horizontal-extension));
1119
1124
  }
1120
1125
 
1121
- .capra-Switch-module-16LYpW-switch:checked:not(:disabled):active:before {
1126
+ .capra-Switch-module-j8Yc-q-switch:checked:not(:disabled):active:before {
1122
1127
  left: calc(var(--_cds-switch-handle-checked-left) - var(--_cds-switch-handle-horizontal-extension));
1123
1128
  }
1124
1129
 
1125
1130
  @media (prefers-reduced-motion: reduce) {
1126
- .capra-Switch-module-16LYpW-switch, .capra-Switch-module-16LYpW-switch:before {
1131
+ .capra-Switch-module-j8Yc-q-switch, .capra-Switch-module-j8Yc-q-switch:before {
1127
1132
  transition: none;
1128
1133
  }
1129
1134
  }
@@ -2014,6 +2019,337 @@ input:disabled + .capra-Radio-module-ZI7rzq-inner:after {
2014
2019
  color: var(--cds2-color-foreground-danger-default);
2015
2020
  margin-block-start: var(--cds2-spacing-xs);
2016
2021
  }
2022
+ .capra-SelectField-module-1X4diq-triggerShell {
2023
+ border: var(--cds2-border-default);
2024
+ border-radius: var(--cds2-radius-md);
2025
+ background-color: var(--cds2-temporary-input-background-primary);
2026
+ width: 100%;
2027
+ min-width: 0;
2028
+ color: var(--cds2-temporary-input-foreground-primary);
2029
+ transition: border-color var(--cds2-motion-duration-short) ease,
2030
+ box-shadow var(--cds2-motion-duration-short) ease;
2031
+ align-items: center;
2032
+ display: inline-flex;
2033
+
2034
+ &:not([data-disabled="true"]):hover {
2035
+ border-color: var(--cds2-temporary-input-border-highlight);
2036
+ }
2037
+
2038
+ &[data-size="sm"] {
2039
+ min-height: var(--cds2-dimension-component-sm);
2040
+ padding-inline: var(--cds2-spacing-md);
2041
+ font: var(--cds2-typography-body-sm-normal);
2042
+ }
2043
+
2044
+ &[data-size="md"] {
2045
+ min-height: var(--cds2-dimension-component-md);
2046
+ gap: var(--cds2-spacing-md);
2047
+ padding-inline: var(--cds2-spacing-md);
2048
+ font: var(--cds2-typography-body-md-normal);
2049
+ }
2050
+
2051
+ &[data-disabled="true"] {
2052
+ background-color: var(--cds2-temporary-input-background-disabled);
2053
+ border-color: var(--cds2-temporary-input-border-disabled);
2054
+ color: var(--cds2-temporary-input-foreground-disabled);
2055
+ cursor: not-allowed;
2056
+
2057
+ & .capra-SelectField-module-1X4diq-leadingSlot, & .capra-SelectField-module-1X4diq-trailingSlot, & .capra-SelectField-module-1X4diq-valueText, & .capra-SelectField-module-1X4diq-tag {
2058
+ color: var(--cds2-temporary-input-foreground-disabled);
2059
+ }
2060
+ }
2061
+ }
2062
+
2063
+ .capra-SelectField-module-1X4diq-singleTrigger {
2064
+ &:focus-visible {
2065
+ outline: var(--cds2-border-focus);
2066
+ outline-offset: var(--cds2-spacing-xs);
2067
+ }
2068
+ }
2069
+
2070
+ .capra-SelectField-module-1X4diq-multipleTrigger {
2071
+ overflow: hidden;
2072
+
2073
+ &:has(.capra-SelectField-module-1X4diq-multipleOpenButton:focus-visible) {
2074
+ outline: var(--cds2-border-focus);
2075
+ outline-offset: var(--cds2-spacing-xs);
2076
+ }
2077
+
2078
+ &[data-empty]:not([data-disabled="true"]) {
2079
+ cursor: pointer;
2080
+ }
2081
+ }
2082
+
2083
+ .capra-SelectField-module-1X4diq-multipleOpenButton {
2084
+ color: inherit;
2085
+ cursor: pointer;
2086
+ background: none;
2087
+ border: none;
2088
+ flex-shrink: 0;
2089
+ align-items: center;
2090
+ margin: 0;
2091
+ padding: 0;
2092
+ display: inline-flex;
2093
+
2094
+ &[data-disabled="true"] {
2095
+ cursor: not-allowed;
2096
+ }
2097
+
2098
+ &:focus {
2099
+ outline: none;
2100
+ }
2101
+ }
2102
+
2103
+ .capra-SelectField-module-1X4diq-leadingSlot, .capra-SelectField-module-1X4diq-trailingSlot {
2104
+ align-items: center;
2105
+ gap: var(--cds2-spacing-md);
2106
+ color: var(--cds2-color-foreground-subtle);
2107
+ flex-shrink: 0;
2108
+ display: inline-flex;
2109
+ }
2110
+
2111
+ .capra-SelectField-module-1X4diq-value {
2112
+ align-items: center;
2113
+ gap: var(--cds2-spacing-sm);
2114
+ flex: auto;
2115
+ min-width: 0;
2116
+ display: flex;
2117
+ }
2118
+
2119
+ .capra-SelectField-module-1X4diq-valueIcon {
2120
+ color: var(--cds2-color-foreground-subtle);
2121
+ flex-shrink: 0;
2122
+ align-items: center;
2123
+ display: inline-flex;
2124
+ }
2125
+
2126
+ .capra-SelectField-module-1X4diq-valueText {
2127
+ text-overflow: ellipsis;
2128
+ white-space: nowrap;
2129
+ min-width: 0;
2130
+ overflow: hidden;
2131
+
2132
+ &[data-placeholder] {
2133
+ color: var(--cds2-temporary-input-foreground-placeholder);
2134
+ }
2135
+ }
2136
+
2137
+ .capra-SelectField-module-1X4diq-tagGroup {
2138
+ flex: auto;
2139
+ min-width: 0;
2140
+ display: flex;
2141
+ }
2142
+
2143
+ .capra-SelectField-module-1X4diq-tagList {
2144
+ gap: var(--cds2-spacing-xs);
2145
+ min-width: 0;
2146
+ padding-block: var(--cds2-spacing-xs);
2147
+ outline: none;
2148
+ flex-wrap: wrap;
2149
+ flex: auto;
2150
+ display: flex;
2151
+
2152
+ &[data-focus-visible] {
2153
+ outline: none;
2154
+ }
2155
+
2156
+ & > * {
2157
+ flex-shrink: 0;
2158
+ }
2159
+ }
2160
+
2161
+ .capra-SelectField-module-1X4diq-tag {
2162
+ justify-content: space-between;
2163
+ align-items: center;
2164
+ gap: var(--cds2-spacing-sm);
2165
+ padding: 0 var(--cds2-spacing-md);
2166
+ border-radius: var(--cds2-radius-md);
2167
+ border: var(--cds2-border-default);
2168
+ border-color: var(--cds2-color-border-neutral-subtle);
2169
+ background-color: var(--cds2-color-background-neutral-subtle);
2170
+ color: var(--cds2-color-foreground-subtle);
2171
+ cursor: default;
2172
+ outline: none;
2173
+ display: inline-flex;
2174
+
2175
+ &[data-size="md"] {
2176
+ height: var(--cds2-dimension-component-sm);
2177
+ min-width: var(--cds2-dimension-component-sm);
2178
+ font: var(--cds2-typography-body-sm-normal);
2179
+ }
2180
+
2181
+ &[data-size="sm"] {
2182
+ height: var(--cds2-dimension-component-xs);
2183
+ min-width: var(--cds2-dimension-component-xs);
2184
+ font: var(--cds2-typography-body-xs-normal);
2185
+ }
2186
+
2187
+ &[data-focus-visible] {
2188
+ outline: var(--cds2-border-focus);
2189
+ outline-offset: var(--cds2-spacing-xs);
2190
+ }
2191
+
2192
+ &[data-disabled] {
2193
+ opacity: .6;
2194
+ }
2195
+ }
2196
+
2197
+ .capra-SelectField-module-1X4diq-tagIcon {
2198
+ color: var(--cds2-color-foreground-subtle);
2199
+ flex-shrink: 0;
2200
+ align-items: center;
2201
+ display: inline-flex;
2202
+ }
2203
+
2204
+ .capra-SelectField-module-1X4diq-tagLabel {
2205
+ text-overflow: ellipsis;
2206
+ white-space: nowrap;
2207
+ min-width: 0;
2208
+ overflow: hidden;
2209
+ }
2210
+
2211
+ .capra-SelectField-module-1X4diq-tagRemove {
2212
+ width: var(--cds2-dimension-component-xs);
2213
+ height: var(--cds2-dimension-component-xs);
2214
+ border-radius: var(--cds2-radius-md);
2215
+ color: inherit;
2216
+ cursor: pointer;
2217
+ background: none;
2218
+ border: none;
2219
+ flex-shrink: 0;
2220
+ justify-content: center;
2221
+ align-items: center;
2222
+ margin: 0;
2223
+ padding: 0;
2224
+ display: inline-flex;
2225
+
2226
+ &:hover {
2227
+ background-color: var(--cds-color-state-layer-hover);
2228
+ }
2229
+
2230
+ &:focus-visible {
2231
+ outline: var(--cds2-border-focus);
2232
+ outline-offset: var(--cds2-spacing-xs);
2233
+ }
2234
+ }
2235
+
2236
+ .capra-SelectField-module-1X4diq-chevron, .capra-SelectField-module-1X4diq-warningIndicator, .capra-SelectField-module-1X4diq-errorIndicator {
2237
+ justify-content: center;
2238
+ align-items: center;
2239
+ display: inline-flex;
2240
+ }
2241
+
2242
+ .capra-SelectField-module-1X4diq-warningIndicator {
2243
+ color: var(--cds2-color-foreground-warning-default);
2244
+ }
2245
+
2246
+ .capra-SelectField-module-1X4diq-errorIndicator {
2247
+ color: var(--cds2-color-foreground-danger-default);
2248
+ }
2249
+
2250
+ .capra-SelectField-module-1X4diq-dropdownPanel {
2251
+ gap: var(--cds2-spacing-sm);
2252
+ padding: var(--cds2-spacing-sm);
2253
+ border: var(--cds2-border-default);
2254
+ border-color: var(--cds2-color-border-neutral-subtle);
2255
+ border-radius: var(--cds2-radius-md);
2256
+ background: var(--cds2-color-background-panel-solid);
2257
+ box-shadow: var(--cds2-shadow-medium-down);
2258
+ flex-direction: column;
2259
+ display: flex;
2260
+ }
2261
+
2262
+ .capra-SelectField-module-1X4diq-search {
2263
+ width: 100%;
2264
+ }
2265
+
2266
+ .capra-SelectField-module-1X4diq-listbox {
2267
+ gap: var(--cds2-spacing-xs);
2268
+ flex-direction: column;
2269
+ max-height: 320px;
2270
+ display: flex;
2271
+ overflow-y: auto;
2272
+ }
2273
+
2274
+ .capra-SelectField-module-1X4diq-emptyState {
2275
+ padding: var(--cds2-spacing-sm) var(--cds2-spacing-md);
2276
+ color: var(--cds2-color-foreground-subtle);
2277
+ font: var(--cds2-typography-body-md-normal);
2278
+ }
2279
+
2280
+ .capra-SelectField-module-1X4diq-section {
2281
+ display: contents;
2282
+ }
2283
+
2284
+ .capra-SelectField-module-1X4diq-header {
2285
+ box-sizing: border-box;
2286
+ color: var(--cds2-color-foreground-default);
2287
+ font: var(--cds2-typography-body-md-semibold);
2288
+ padding: var(--cds2-spacing-sm) var(--cds2-spacing-md);
2289
+ align-items: center;
2290
+ width: 100%;
2291
+ display: flex;
2292
+ }
2293
+
2294
+ .capra-SelectField-module-1X4diq-dropdownPanel:focus-visible, .capra-SelectField-module-1X4diq-listbox:focus-visible {
2295
+ outline: none;
2296
+ }
2297
+
2298
+ .capra-SelectField-module-1X4diq-item {
2299
+ border-radius: var(--cds2-radius-md);
2300
+ outline: none;
2301
+
2302
+ &:focus {
2303
+ outline: none;
2304
+ }
2305
+
2306
+ &[data-indent="true"] {
2307
+ padding-inline-start: var(--cds2-spacing-xl);
2308
+ }
2309
+
2310
+ &[data-focused="true"] {
2311
+ background-color: var(--cds-color-state-layer-hover);
2312
+ }
2313
+
2314
+ &[data-selected="true"] {
2315
+ background-color: var(--cds-color-state-layer-accent-selected);
2316
+ color: var(--cds2-color-foreground-default);
2317
+ }
2318
+
2319
+ .capra-SelectField-module-1X4diq-listbox[data-selection-mode="multiple"] &[data-selected="true"] {
2320
+ color: var(--cds2-color-foreground-default);
2321
+ background: none;
2322
+ }
2323
+
2324
+ .capra-SelectField-module-1X4diq-listbox[data-selection-mode="multiple"] &[data-focused="true"] {
2325
+ background-color: var(--cds-color-state-layer-hover);
2326
+ }
2327
+
2328
+ &[data-disabled="true"] {
2329
+ background: var(--cds2-color-background-disabled);
2330
+ color: var(--cds2-color-foreground-on-disabled);
2331
+ }
2332
+ }
2333
+
2334
+ .capra-SelectField-module-1X4diq-itemContent {
2335
+ align-items: center;
2336
+ gap: var(--cds2-spacing-sm);
2337
+ padding: var(--cds2-spacing-sm) var(--cds2-spacing-md);
2338
+ display: flex;
2339
+ }
2340
+
2341
+ .capra-SelectField-module-1X4diq-itemCheck {
2342
+ width: var(--cds2-dimension-icon-md);
2343
+ min-width: var(--cds2-dimension-icon-md);
2344
+ color: var(--cds2-color-foreground-default);
2345
+ justify-content: center;
2346
+ align-items: center;
2347
+ display: inline-flex;
2348
+
2349
+ .capra-SelectField-module-1X4diq-item[data-disabled="true"] & {
2350
+ color: var(--cds2-color-foreground-on-disabled);
2351
+ }
2352
+ }
2017
2353
  .capra-DateRangePickerField-module-QpPhpG-dateRangeInputShell[data-show-string-placeholder="true"] .capra-DateRangePickerField-module-QpPhpG-dateInputsRow {
2018
2354
  opacity: 0;
2019
2355
  }
@@ -5,7 +5,7 @@ AutocompleteField combines a text field with a suggestions list. Consumers can s
5
5
  | Prop | Type | Required | Default | Description |
6
6
  | --- | --- | --- | --- | --- |
7
7
  | `canClear` | `boolean` | No | `--` | Whether to show a clear button for the input. |
8
- | `children` | `React.ReactNode \| (( values: T & { defaultChildren: React.ReactNode \| undefined; }, ) => React.ReactNode)` | No | `--` | The children to render in the dropdown. |
8
+ | `children` | `ChildrenOrFunction` | No | `--` | The children to render in the dropdown. |
9
9
  | `itemFilter` | `(textValue: string, inputValue: string) => boolean` | No | `--` | A function that filters the items based on the input value. |
10
10
  | `onChange` | `(value: string) => void` | No | `--` | A callback function that is called when the input value changes. |
11
11
  | `onOpenChange` | `(isOpen: boolean) => void` | No | `--` | A callback function that is called when the dropdown is opened or closed. |
@@ -0,0 +1,66 @@
1
+ # Core/SelectField - Design
2
+
3
+ ## Anatomy
4
+
5
+ 1. **Label**: describes the field and carries the required marker when needed.
6
+ 2. **Trigger**: matches Capra text-input sizing and state treatments.
7
+ 3. **Popover**: contains the option list and optional search field.
8
+ 4. **ListBox items**: support single-select rows or multi-select rows with checkmarks.
9
+ 5. **Sections**: optional grouped options with a non-selectable header label.
10
+
11
+ ## Properties
12
+
13
+ ### Layout
14
+
15
+ Use `layout="vertical"` by default. Use `layout="horizontal"` only when space is constrained.
16
+
17
+ ### Multiple Selection
18
+
19
+ For multi-select fields, selected options appear as removable tags inside the trigger. Tags wrap onto additional lines when they exceed the field width, and selected rows show a checkmark in the popover.
20
+
21
+ ### Search
22
+
23
+ Enable `canSearch` for longer option lists. Search filters the visible options inside the popover without changing the trigger layout. When nothing matches, the popover shows "No results" so the list never appears empty.
24
+
25
+ ### Sections
26
+
27
+ Larger option lists can be organized into smaller groups using sections. Each section has a header to label the grouping. Pass `items` with nested `children` to build sections from data, or wrap static options in `SelectField.Section` with a `SelectField.Header`.
28
+
29
+ ## States
30
+
31
+ * Match the standard input states: default, hover, focus, disabled, placeholder, warning, and danger.
32
+ * `appearance="danger"` drives the invalid visual state and helper text treatment.
33
+ * Small and medium sizes align with `TextInput`.
34
+
35
+ ## Behavior
36
+
37
+ * Use `SelectField` for fixed option sets, especially when the option count is greater than about five.
38
+ * Prefer `RadioGroup` when the user should see all mutually exclusive choices at once.
39
+ * Prefer `AutocompleteField` when freeform typing or custom values are required.
40
+
41
+ ## Accessibility
42
+
43
+ ### Keyboard interaction
44
+
45
+ | Key | Function |
46
+ | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
47
+ | `Tab` / `Shift + Tab` | Moves focus into the multiselect TagGroup (first selected tag) or the open button, then to the next or previous focusable element. Remove buttons are not sequential tab stops. If the option list is open, these keys are ignored. |
48
+ | `Left Arrow` / `Right Arrow` | In multiple-select mode with the TagGroup focused: moves focus between selected tags. |
49
+ | `Delete` / `Backspace` | In multiple-select mode with a selected tag focused: removes that tag. |
50
+ | `Down Arrow` / `Up Arrow` | If the option list is closed and the open button has focus: opens the list and moves focus to the selected item (the first selected item in multiple-select mode), or the first/last item when nothing is selected. If the list is open: moves focus to the next or previous option. |
51
+ | `Enter` / `Space` | If the option list is closed: opens the option list (from the open button). If the list is open: selects the focused option. In single-select mode the list closes after selection; in multiple-select mode the list stays open. |
52
+ | `Esc` | If the option list is open: closes the list and returns focus to the select trigger. |
53
+
54
+ While the option list is open, focus stays inside the popover in both selection modes.
55
+
56
+ In multiple-select mode, selected values use React Aria’s `TagGroup` in the trigger (styled to match Capra Tag). Keyboard behavior follows TagGroup defaults: arrows move between tags; Delete/Backspace removes; clicking the remove control also removes.
57
+
58
+ ### Labeling
59
+
60
+ All select fields require a label. Provide a visible `label` prop when possible. When a visible label is not spatially associated with the trigger, use `aria-label` or `aria-labelledby`.
61
+
62
+ ### Focus treatment
63
+
64
+ * The trigger uses the Capra 2px focus outline (`token('border.focus')`).
65
+ * List options show a keyboard focus ring on the active row; the popover container suppresses the browser default panel outline (same pattern as `Menu`).
66
+ * Warning and danger icons in the trigger are decorative (`aria-hidden`); invalid state is conveyed with `aria-invalid` on the trigger.
@@ -0,0 +1,145 @@
1
+ # Core/SelectField - Usage
2
+
3
+ ## Basic usage
4
+
5
+ ```tsx
6
+ import { SelectField } from '@private/core';
7
+
8
+ const animals = [
9
+ { id: '1', label: 'Dog' },
10
+ { id: '2', label: 'Cat' },
11
+ { id: '3', label: 'Bird' },
12
+ ];
13
+
14
+ function Example() {
15
+ return (
16
+ <SelectField label="Animal" placeholder="Select" items={animals} />
17
+ );
18
+ }
19
+ ```
20
+
21
+ ## Props
22
+
23
+ ## Examples
24
+
25
+ ### Single select
26
+
27
+ Pass `items` to render a list of options. Each item should have an `id` and a `label` property if using the default item renderer. You can also pass a custom item renderer to render each item as you need (see [Custom item renderer](#custom-item-renderer)).
28
+
29
+ ```tsx
30
+ const animals = [
31
+ { id: '1', label: 'Dog' },
32
+ { id: '2', label: 'Cat' },
33
+ { id: '3', label: 'Bird' },
34
+ ];
35
+
36
+ <SelectField label="Animal" placeholder="Select" items={animals} />
37
+ ```
38
+
39
+ ### Multiple select
40
+
41
+ Set `selectionMode="multiple"` when more than one value can be selected. Selected options render as tags in the input.
42
+
43
+ ```tsx
44
+ const states = [
45
+ { id: '1', label: 'California' },
46
+ { id: '2', label: 'New York' },
47
+ { id: '3', label: 'Texas' },
48
+ ];
49
+
50
+ <SelectField label="States" selectionMode="multiple" defaultValue={['CA', 'NY']} items={states} />
51
+ ```
52
+
53
+ ### Custom item renderer
54
+
55
+ When the default item renderer doesn't meet your needs, you can provide a custom item renderer. Each item **must** be a `SelectField.Item` or `SelectField.Section` component. `SelectField.Item` should be passed an `id` and `textValue` prop. `textValue` is used for typeahead and accessibility naming.
56
+
57
+ :::warning
58
+
59
+ For performance reasons, custom item renderers are cached on component mount. Custom item render functions should be pure functions that take only the passed item as an argument. Any reliance on external state or props will mostly likely cause unexpected and undesired behavior.
60
+
61
+ :::
62
+
63
+ ```tsx
64
+ const users = [
65
+ { id: '1', name: 'Malcolm Reynolds', email: 'malcolm.reynolds@example.com' },
66
+ { id: '2', name: 'Inara Serra', email: 'inara.serra@example.com' },
67
+ { id: '3', name: 'Kaylee Frye', email: 'kaylee.frye@example.com' },
68
+ ];
69
+
70
+ <SelectField label="Users" selectionMode="multiple" defaultValue={['1', '2']} items={users}>
71
+ {(user) => (
72
+ <SelectField.Item id={user.id} textValue={user.name}>
73
+ <div>{user.name}</div>
74
+ <div>{user.email}</div>
75
+ </SelectField.Item>
76
+ )}
77
+ </SelectField>
78
+ ```
79
+
80
+ ### Searchable options
81
+
82
+ Enable `canSearch` for longer lists so users can filter options inside the popover.
83
+
84
+ ```tsx
85
+ const categories = [
86
+ { id: '1', name: 'Electronics' },
87
+ { id: '2', name: 'Clothing' },
88
+ { id: '3', name: 'Books' },
89
+ // ...
90
+ { id: '100', name: 'Other' },
91
+ ];
92
+
93
+ <SelectField label="Category" items={categories} canSearch searchPlaceholder="Search categories">
94
+ {(item) => (
95
+ <SelectField.Item id={item.id} textValue={item.name}>
96
+ {item.name}
97
+ </SelectField.Item>
98
+ )}
99
+ </SelectField>
100
+ ```
101
+
102
+ When a search matches none of the options, the popover shows "No results" in place of the option list.
103
+
104
+ ### Sections
105
+
106
+ Organize larger option lists into labeled groups by passing `items` with nested `children`, using the default item renderer. If a section has no visible `label`, provide `aria-label` on the section.
107
+
108
+ ```tsx
109
+ const items = [
110
+ {
111
+ id: 'fruit',
112
+ label: 'Fruit',
113
+ children: [
114
+ { id: 'apple', label: 'Apple' },
115
+ { id: 'banana', label: 'Banana' },
116
+ ],
117
+ },
118
+ {
119
+ id: 'veg',
120
+ label: 'Vegetable',
121
+ children: [
122
+ { id: 'broccoli', label: 'Broccoli' },
123
+ { id: 'carrots', label: 'Carrots' },
124
+ ],
125
+ },
126
+ ];
127
+
128
+ <SelectField label="Healthy Snack" placeholder="Select an item" items={items} />
129
+ ```
130
+
131
+ Sections can also be built with `SelectField.Section` and `SelectField.Header` JSX children when using static options instead of `items`.
132
+
133
+ ### Item icons
134
+
135
+ When an item has an `icon`, it renders before the label in the list. Selecting that item also shows the icon in the trigger for single select, or in the tag for multiple select.
136
+
137
+ ```tsx
138
+ const items = [
139
+ { id: '1', label: 'Favorites', icon: StarIcon },
140
+ { id: '2', label: 'Settings', icon: CogIcon },
141
+ { id: '3', label: 'Help', icon: HelpIcon },
142
+ ];
143
+
144
+ <SelectField label="Menu" items={items} />
145
+ ```
@@ -1,5 +1,15 @@
1
1
  # History/Changelogs/@capra-core
2
2
 
3
+ ### 1.13.0
4
+
5
+ #### Minor Changes
6
+
7
+ * [159e15b](https://bitbucket.org/cribl/capra-ui/commits/159e15b): Add a `SelectField` component.
8
+
9
+ #### Patch Changes
10
+
11
+ * [28df32f](https://bitbucket.org/cribl/capra-ui/commits/28df32f): Fix Switch background colors
12
+
3
13
  ### 1.12.0
4
14
 
5
15
  #### Minor Changes