asma-ui-core 3.3.11 → 3.4.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.
@@ -1,2 +1,155 @@
1
1
  import type { StyledDynamicSelectComponent } from './types';
2
+ /**
3
+ * A smart, adaptive select input that automatically chooses the best UI representation
4
+ * based on the number of options provided.
5
+ *
6
+ * **Rendering strategy:**
7
+ * - `1–5 options` → renders as an interactive chip group (`DynamicInteractiveChipGroup`).
8
+ * Chips behave as radio buttons (single) or checkboxes (multiple).
9
+ * Long labels automatically switch to a vertical stacked layout.
10
+ * When `!required` and a value is selected, a "Clear selection" button is shown.
11
+ * - `0 or 6+ options` → renders as a searchable autocomplete (`DynamicSelectAutocomplete`).
12
+ * Typing is disabled when there are ≤10 options (caret hidden, keyboard blocked).
13
+ *
14
+ * **Option types:**
15
+ * Options can be primitives (`string | number | boolean`) or objects. When using objects,
16
+ * the component reads `option.value` and `option.label` by default. Override with
17
+ * `valueKey` and `labelKey` to use different keys. Individual options can be disabled
18
+ * by setting `option.disabled = true`.
19
+ *
20
+ * @template TOption – The option type. Must extend `DynamicSelectOption`.
21
+ *
22
+ * ---
23
+ *
24
+ * @example
25
+ * // 1. Single select – primitive strings (chip group for ≤5, autocomplete for 6+)
26
+ * const [value, setValue] = useState<string | null>(null)
27
+ *
28
+ * <StyledDynamicSelect
29
+ * dataTest="status-select"
30
+ * options={['Active', 'Inactive', 'Pending']}
31
+ * value={value}
32
+ * onChange={setValue}
33
+ * />
34
+ *
35
+ * ---
36
+ *
37
+ * @example
38
+ * // 2. Single select – object options with default value/label keys
39
+ * type Status = { value: string; label: string; disabled?: boolean }
40
+ * const statuses: Status[] = [
41
+ * { value: 'active', label: 'Active' },
42
+ * { value: 'inactive', label: 'Inactive', disabled: true },
43
+ * ]
44
+ * const [status, setStatus] = useState<Status | null>(null)
45
+ *
46
+ * <StyledDynamicSelect
47
+ * dataTest="status-select"
48
+ * options={statuses}
49
+ * value={status}
50
+ * onChange={setStatus}
51
+ * title="Status"
52
+ * required
53
+ * error={!status}
54
+ * helperText="Status is required"
55
+ * />
56
+ *
57
+ * ---
58
+ *
59
+ * @example
60
+ * // 3. Multiple select – object options with custom keys
61
+ * type User = { id: string; fullName: string; disabled?: boolean }
62
+ * const users: User[] = [
63
+ * { id: '1', fullName: 'Alice Smith' },
64
+ * { id: '2', fullName: 'Bob Jones', disabled: true },
65
+ * ]
66
+ * const [selected, setSelected] = useState<User[] | null>([])
67
+ *
68
+ * <StyledDynamicSelect
69
+ * dataTest="assignee-select"
70
+ * options={users}
71
+ * value={selected}
72
+ * onChange={setSelected}
73
+ * multiple
74
+ * valueKey="id"
75
+ * labelKey="fullName"
76
+ * title="Assignees"
77
+ * placeholder="Search users…"
78
+ * maxTags={3}
79
+ * />
80
+ *
81
+ * ---
82
+ *
83
+ * @example
84
+ * // 4. Read-only display – only selected options are shown
85
+ * <StyledDynamicSelect
86
+ * dataTest="status-readonly"
87
+ * options={statuses}
88
+ * value={selectedStatus}
89
+ * onChange={() => {}}
90
+ * readOnly
91
+ * />
92
+ *
93
+ * ---
94
+ *
95
+ * @example
96
+ * // 5. Custom label renderer (e.g. with avatar or description)
97
+ * <StyledDynamicSelect
98
+ * dataTest="user-select"
99
+ * options={users}
100
+ * value={selected}
101
+ * onChange={setSelected}
102
+ * multiple
103
+ * valueKey="id"
104
+ * labelKey="fullName"
105
+ * renderLabel={(user) => (
106
+ * <span className="flex items-center gap-2">
107
+ * <Avatar src={user.avatarUrl} size={20} />
108
+ * {user.fullName}
109
+ * </span>
110
+ * )}
111
+ * />
112
+ *
113
+ * ---
114
+ *
115
+ * @example
116
+ * // 6. Per-option tooltip
117
+ * <StyledDynamicSelect
118
+ * dataTest="plan-select"
119
+ * options={plans}
120
+ * value={selectedPlan}
121
+ * onChange={setSelectedPlan}
122
+ * getOptionTooltip={(plan) =>
123
+ * plan.disabled ? 'Upgrade your subscription to unlock this plan' : null
124
+ * }
125
+ * />
126
+ *
127
+ * ---
128
+ *
129
+ * @example
130
+ * // 7. Loading state (skeletons in chip group, disabled in autocomplete)
131
+ * <StyledDynamicSelect
132
+ * dataTest="category-select"
133
+ * options={categories}
134
+ * value={value}
135
+ * onChange={setValue}
136
+ * loading={isFetching}
137
+ * />
138
+ *
139
+ * ---
140
+ *
141
+ * @example
142
+ * // 8. Forwarded ref – focus the input programmatically
143
+ * const ref = useRef<HTMLInputElement>(null)
144
+ *
145
+ * <StyledDynamicSelect
146
+ * ref={ref}
147
+ * dataTest="search-select"
148
+ * options={options}
149
+ * value={value}
150
+ * onChange={setValue}
151
+ * />
152
+ *
153
+ * <button onClick={() => ref.current?.focus()}>Focus</button>
154
+ */
2
155
  export declare const StyledDynamicSelect: StyledDynamicSelectComponent;
@@ -18,25 +18,75 @@ type MultipleDynamicSelectProps<TOption extends DynamicSelectOption> = {
18
18
  onChange: (value: TOption[] | null) => void;
19
19
  };
20
20
  type DynamicSelectCommonProps<TOption extends DynamicSelectOption> = {
21
+ /** Unique identifier used as the root `data-test` attribute for QA selectors. */
21
22
  dataTest: string;
23
+ /** The full list of selectable options. Determines which UI is rendered: 1–5 → chip group, 0 or 6+ → autocomplete. */
22
24
  options: TOption[];
25
+ /** When `true`, the component is non-interactive and only shows selected value(s) as plain chip(s). */
23
26
  readOnly?: boolean;
27
+ /** Prevents the built-in clear button from appearing even when a value is set. Applies to autocomplete only. */
24
28
  disableClearable?: boolean;
29
+ /** Optional label rendered above the input/chip group. */
25
30
  title?: string;
31
+ /** Controls the visual size of chips and buttons. Defaults to `'medium'`. */
26
32
  size?: 'small' | 'medium';
33
+ /** Placeholder text shown in the autocomplete input when no value is selected. */
27
34
  placeholder?: string;
35
+ /** Disables all interactions. */
28
36
  disabled?: boolean;
37
+ /** Text shown in the autocomplete dropdown when no options match the search query. */
29
38
  noOptionsText?: string;
39
+ /** When `true`, shows the error style and renders an error icon next to the helper text. */
30
40
  error?: boolean;
41
+ /**
42
+ * When `true`, hides the "Clear selection" button in the chip group.
43
+ * Use this when the field must always have a value.
44
+ */
45
+ required?: boolean;
46
+ /** Supplementary text rendered below the input. Shown as-is, or falls back to `'Required'` when `error=true` and no text is provided. */
31
47
  helperText?: React.ReactNode;
48
+ /**
49
+ * Key of `TOption` used as the option's identity for comparison and as the chip/tag key.
50
+ * Defaults to `'value'`. Only applicable when `TOption` is an object.
51
+ */
32
52
  valueKey?: TOption extends object ? keyof TOption : never;
53
+ /**
54
+ * Key of `TOption` used as the displayed label string.
55
+ * Defaults to `'label'`. Only applicable when `TOption` is an object.
56
+ */
33
57
  labelKey?: TOption extends object ? keyof TOption : never;
58
+ /**
59
+ * Custom label renderer. When provided, its return value is used instead of the
60
+ * plain string resolved from `labelKey`. Useful for rich content (icons, avatars, etc.).
61
+ */
34
62
  renderLabel?: (option: TOption) => React.ReactNode;
63
+ /**
64
+ * Returns a tooltip node shown when hovering a specific option.
65
+ * Return `null` to show no tooltip for that option.
66
+ */
35
67
  getOptionTooltip?: (option: TOption) => React.ReactNode;
68
+ /** Node prepended inside the autocomplete text input (e.g. a search icon). */
36
69
  startAdornment?: React.ReactNode;
70
+ /** Escape hatch to pass any MUI `Autocomplete` prop directly. Applied on top of internal defaults in the autocomplete variant. */
37
71
  autocompleteProps?: Partial<AutocompleteProps<TOption, boolean | undefined, boolean | undefined, boolean | undefined>>;
72
+ /**
73
+ * When `true`, renders loading skeletons (chip group) or disables the input (autocomplete)
74
+ * while data is being fetched.
75
+ */
38
76
  loading?: boolean;
77
+ /**
78
+ * Limits how many selected-value chips are visible in the autocomplete's input area.
79
+ * Remaining selections are summarised as `+N`. Has no effect on the chip group variant.
80
+ */
39
81
  maxTags?: number;
82
+ /**
83
+ * Controls locale-sensitive labels and messages used by the component.
84
+ * Use `'no'` for Norwegian and `'en'` for English.
85
+ *
86
+ * Intended for consumer-facing text such as clear actions, helper copy,
87
+ * or empty-state messaging when localized behavior is supported.
88
+ */
89
+ locale?: 'no' | 'en';
40
90
  };
41
91
  export type StyledDynamicSelectProps<TOption extends DynamicSelectOption> = DynamicSelectCommonProps<TOption> & (SingleDynamicSelectProps<TOption> | MultipleDynamicSelectProps<TOption>);
42
92
  export type StyledDynamicSelectComponent = <TOption extends DynamicSelectOption>(props: StyledDynamicSelectProps<TOption> & React.RefAttributes<HTMLInputElement>) => React.ReactElement | null;