@kismet-ux/constellation 1.7.0 → 1.9.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 (41) hide show
  1. package/README.md +36 -0
  2. package/dist/form/Input/input.css +32 -0
  3. package/dist/form/Input/input.d.ts +18 -1
  4. package/dist/form/Input/input.d.ts.map +1 -1
  5. package/dist/form/Input/input.js +20 -2
  6. package/dist/form/Input/input.js.map +1 -1
  7. package/dist/form/Input/input.module.scss.js +1 -1
  8. package/dist/form/Select/select.css +9 -0
  9. package/dist/form/Select/select.d.ts +11 -1
  10. package/dist/form/Select/select.d.ts.map +1 -1
  11. package/dist/form/Select/select.js +10 -2
  12. package/dist/form/Select/select.js.map +1 -1
  13. package/dist/form/Select/select.module.scss.js +1 -1
  14. package/dist/form.d.ts +2 -2
  15. package/dist/{index-Bexoc2w4.d.ts → index-CRrCqjAW.d.ts} +13 -3
  16. package/dist/{index-K2b259WI.d.ts → index-Mihuyg_o.d.ts} +4 -2
  17. package/dist/{index-IHzHSsCh.d.ts → index-ZgohDspB.d.ts} +14 -14
  18. package/dist/index.d.ts +13 -55
  19. package/dist/{input-CWHXOpeH.d.ts → input-Cp5LET5i.d.ts} +17 -0
  20. package/dist/layout/Container/container.css +1 -1
  21. package/dist/layout/Container/container.d.ts.map +1 -1
  22. package/dist/layout/Container/container.js +5 -2
  23. package/dist/layout/Container/container.js.map +1 -1
  24. package/dist/layout/Sidebar/sidebar.d.ts.map +1 -1
  25. package/dist/layout/Sidebar/sidebar.js.map +1 -1
  26. package/dist/layout.d.ts +3 -3
  27. package/dist/navigation.d.ts +1 -1
  28. package/dist/{tooltip-CYRWWtkq.d.ts → tooltip-cjwkBINy.d.ts} +5 -1
  29. package/dist/types/layout/container.d.ts +2 -0
  30. package/dist/types/layout/container.d.ts.map +1 -1
  31. package/dist/ui/Button/button-variants.d.ts +1 -1
  32. package/dist/ui/Button/button.css +92 -77
  33. package/dist/ui/Button/button.d.ts +4 -0
  34. package/dist/ui/Button/button.d.ts.map +1 -1
  35. package/dist/ui/Button/button.js +8 -2
  36. package/dist/ui/Button/button.js.map +1 -1
  37. package/dist/ui/Icon/icon-variants.d.ts +1 -1
  38. package/dist/ui/Toggle/toggle-variants.d.ts +1 -1
  39. package/dist/ui.d.ts +2 -2
  40. package/package.json +1 -1
  41. package/vite-plugin.mjs +7 -2
package/README.md CHANGED
@@ -154,6 +154,42 @@ Each component is a folder: `component-name.tsx` + `component-name.module.scss`
154
154
 
155
155
  ---
156
156
 
157
+ ## Developing it against a real app
158
+
159
+ Publishing a version for every small change is how versioning goes off the rails. Instead, point a consuming app at a sibling checkout:
160
+
161
+ ```
162
+ projects/
163
+ kismet-constellation/ ← this repo
164
+ your-app/
165
+ ```
166
+
167
+ In the app's `vite.config.js`:
168
+
169
+ ```js
170
+ import constellationLocal from '@kismet-ux/constellation/vite';
171
+
172
+ export default defineConfig({
173
+ plugins: [constellationLocal({ root: '../kismet-constellation' }), react()],
174
+ });
175
+ ```
176
+
177
+ …and in its `.env.local`:
178
+
179
+ ```
180
+ CONSTELLATION_LOCAL=true
181
+ ```
182
+
183
+ The plugin builds resolve aliases from this package's own `exports` map, so there is no alias list to maintain. It aliases to `dist`, so keep a build running:
184
+
185
+ ```bash
186
+ npx rollup -c --watch
187
+ ```
188
+
189
+ `__CONSTELLATION_LOCAL__` is defined as `true` while it is on, which is what `DevIndicator` reads to show its badge. With the variable unset the plugin is inert and the app uses the published package, so nothing depends on the checkout existing.
190
+
191
+ ⚠️ **The plugin appends to `server.fs.allow`, and must.** Setting that option at all replaces Vite's default, so listing only the library root locks the consuming app out of its own source — every module 403s and the page renders blank with no useful error.
192
+
157
193
  ## Commands
158
194
 
159
195
  ```bash
@@ -46,6 +46,30 @@
46
46
  transition: border-color 0.3s ease, box-shadow 0.3s ease;
47
47
  width: 100%;
48
48
  }
49
+ .input-module_container__bycn1 .input-module_input-container__nw0Oc .input-module_ghost-wrap__pHzia {
50
+ display: flex;
51
+ flex-grow: 1;
52
+ min-width: 0;
53
+ position: relative;
54
+ }
55
+ .input-module_container__bycn1 .input-module_input-container__nw0Oc {
56
+ /*
57
+ * Shares the field's box exactly: same font (inherited), `inset: 0` on a
58
+ * wrapper that IS the field's box, and `white-space: pre` so runs of
59
+ * spaces in the tail are not collapsed away and the offset stays true.
60
+ */
61
+ }
62
+ .input-module_container__bycn1 .input-module_input-container__nw0Oc .input-module_ghost__yVtI- {
63
+ color: var(--text-disabled);
64
+ inset: 0;
65
+ overflow: hidden;
66
+ pointer-events: none;
67
+ position: absolute;
68
+ white-space: pre;
69
+ }
70
+ .input-module_container__bycn1 .input-module_input-container__nw0Oc .input-module_ghost-typed__r9NZN {
71
+ visibility: hidden;
72
+ }
49
73
  .input-module_container__bycn1 .input-module_input-container__nw0Oc input,
50
74
  .input-module_container__bycn1 .input-module_input-container__nw0Oc textarea {
51
75
  background: none;
@@ -55,6 +79,14 @@
55
79
  font-size: inherit;
56
80
  min-width: 0;
57
81
  outline: none !important;
82
+ }
83
+ .input-module_container__bycn1 .input-module_input-container__nw0Oc input--ghosted,
84
+ .input-module_container__bycn1 .input-module_input-container__nw0Oc textarea--ghosted {
85
+ background: transparent;
86
+ position: relative;
87
+ }
88
+ .input-module_container__bycn1 .input-module_input-container__nw0Oc input,
89
+ .input-module_container__bycn1 .input-module_input-container__nw0Oc textarea {
58
90
  overflow: hidden;
59
91
  padding: 0;
60
92
  text-overflow: ellipsis;
@@ -8,6 +8,23 @@ export interface InputBaseProps {
8
8
  helperText?: string;
9
9
  startAdornment?: React.ReactNode;
10
10
  endAdornment?: React.ReactNode;
11
+ /**
12
+ * Inline completion drawn behind the caret — the TAIL only, not the whole
13
+ * word. `value='Avo'` with `ghost='cado'` reads as "Avocado", the suggestion
14
+ * dimmed.
15
+ *
16
+ * The component owns the alignment; you own the policy. What to suggest and
17
+ * which key accepts it are decisions about your data and your users (a phone
18
+ * has a spacebar under the thumb and no Tab), so they stay with the caller.
19
+ * Accept by setting `value` to the completed string in your own `onKeyDown`.
20
+ *
21
+ * Pass `''` (not `undefined`) for "nothing to suggest right now": the
22
+ * element structure stays stable, so the field is never remounted mid-word.
23
+ *
24
+ * Ignored for `type='textarea'` — a ghost cannot follow a caret across
25
+ * wrapped lines without measuring, which is a different component.
26
+ */
27
+ ghost?: string;
11
28
  }
12
29
  type InputFieldProps = InputBaseProps & React.InputHTMLAttributes<HTMLInputElement> & {
13
30
  type?: Exclude<InputType, 'textarea'>;
@@ -18,6 +35,6 @@ type TextAreaProps = InputBaseProps & React.TextareaHTMLAttributes<HTMLTextAreaE
18
35
  rows?: number;
19
36
  };
20
37
  type InputProps = InputFieldProps | TextAreaProps;
21
- declare const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<HTMLTextAreaElement | HTMLInputElement>>;
38
+ declare const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<HTMLInputElement | HTMLTextAreaElement>>;
22
39
  export { Input };
23
40
  //# sourceMappingURL=input.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../../src/form/Input/input.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,KAAK,SAAS,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAEpC,KAAK,SAAS,GAAG,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,CAAC,MAAM,CAAC,GAAG,UAAU,CAAC;AAElF,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACjC,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAChC;AAED,KAAK,eAAe,GAAG,cAAc,GACnC,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,GAAG;IAC5C,IAAI,CAAC,EAAE,OAAO,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IACtC,IAAI,CAAC,EAAE,KAAK,CAAC;CACd,CAAC;AAEJ,KAAK,aAAa,GAAG,cAAc,GACjC,KAAK,CAAC,sBAAsB,CAAC,mBAAmB,CAAC,GAAG;IAClD,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAGJ,KAAK,UAAU,GAAG,eAAe,GAAG,aAAa,CAAC;AAGlD,QAAA,MAAM,KAAK,2GAwHV,CAAC;AAIF,OAAO,EAAE,KAAK,EAAE,CAAC"}
1
+ {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../../src/form/Input/input.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,KAAK,SAAS,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAEpC,KAAK,SAAS,GAAG,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,CAAC,MAAM,CAAC,GAAG,UAAU,CAAC;AAElF,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACjC,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC/B;;;;;;;;;;;;;;;OAeG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,KAAK,eAAe,GAAG,cAAc,GACnC,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,GAAG;IAC5C,IAAI,CAAC,EAAE,OAAO,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IACtC,IAAI,CAAC,EAAE,KAAK,CAAC;CACd,CAAC;AAEJ,KAAK,aAAa,GAAG,cAAc,GACjC,KAAK,CAAC,sBAAsB,CAAC,mBAAmB,CAAC,GAAG;IAClD,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAGJ,KAAK,UAAU,GAAG,eAAe,GAAG,aAAa,CAAC;AAGlD,QAAA,MAAM,KAAK,2GAgKV,CAAC;AAIF,OAAO,EAAE,KAAK,EAAE,CAAC"}
@@ -7,7 +7,7 @@ import * as React from 'react';
7
7
  import inputStyles from './input.module.scss.js';
8
8
 
9
9
  // The Custom Input Component
10
- const Input = React.forwardRef(({ label, sizeVariant, error = false, helperText, startAdornment, endAdornment, id, type = 'text', rows, onFocus, onBlur, ...rest }, ref) => {
10
+ const Input = React.forwardRef(({ label, sizeVariant, error = false, helperText, startAdornment, endAdornment, id, type = 'text', rows, ghost, onFocus, onBlur, ...rest }, ref) => {
11
11
  const { isBelow } = useBreakpoint();
12
12
  /*
13
13
  * Compose rather than let the caller's handler win.
@@ -32,7 +32,25 @@ const Input = React.forwardRef(({ label, sizeVariant, error = false, helperText,
32
32
  const isTextArea = type === 'textarea';
33
33
  const [isFocused, setIsFocused] = React.useState(false);
34
34
  const containerClasses = cn(inputStyles.container, inputStyles[resolvedSize], { [inputStyles.error]: error }, { [inputStyles.disabled]: rest.disabled }, { [inputStyles.placeholder]: rest.placeholder }, { [inputStyles['is-focused']]: isFocused }, { [inputStyles['has-value']]: rest.value });
35
- return (jsxs("div", { "data-slot": 'input', "data-constellation-field": true, className: containerClasses, children: [jsxs("div", { className: cn(inputStyles['input-container'], isTextArea && inputStyles['textarea-container']), children: [startAdornment && (jsx("span", { "data-slot": 'input-start-adornment', className: inputStyles['adornment'], children: startAdornment })), jsx("div", { className: inputStyles['label-container'], children: jsxs(Label, { htmlFor: inputId, children: [label, (rest['aria-required'] || rest.required) && jsx("span", { className: inputStyles.required, children: "*" })] }) }), isTextArea ? (jsx("textarea", { "data-slot": 'input-field', id: inputId, className: inputStyles['input-field'], "aria-invalid": error ? 'true' : undefined, "aria-describedby": helperId, onFocus: handleFocus, onBlur: handleBlur, ref: ref, rows: rows, ...rest })) : (jsx("input", { "data-slot": 'input-field', id: inputId, className: inputStyles['input-field'], "aria-invalid": error ? 'true' : undefined, "aria-describedby": helperId, onFocus: handleFocus, onBlur: handleBlur, ref: ref, type: type, ...rest })), endAdornment && (jsx("span", { "data-slot": 'input-end-adornment', className: inputStyles['adornment'], children: endAdornment }))] }), helperText && (jsx(Typography, { "data-slot": 'input-helper-text', id: helperId, variant: 'caption', className: inputStyles['helper-text'], children: helperText }))] }));
35
+ return (jsxs("div", { "data-slot": 'input', "data-constellation-field": true, className: containerClasses, children: [jsxs("div", { className: cn(inputStyles['input-container'], isTextArea && inputStyles['textarea-container']), children: [startAdornment && (jsx("span", { "data-slot": 'input-start-adornment', className: inputStyles['adornment'], children: startAdornment })), jsx("div", { className: inputStyles['label-container'], children: jsxs(Label, { htmlFor: inputId, children: [label, (rest['aria-required'] || rest.required) && jsx("span", { className: inputStyles.required, children: "*" })] }) }), isTextArea ? (jsx("textarea", { "data-slot": 'input-field', id: inputId, className: inputStyles['input-field'], "aria-invalid": error ? 'true' : undefined, "aria-describedby": helperId, onFocus: handleFocus, onBlur: handleBlur, ref: ref, rows: rows, ...rest })) : ghost !== undefined ? (
36
+ /*
37
+ * The ghost is drawn by re-rendering the typed value INVISIBLY and
38
+ * letting the suggestion follow it, so the two share one text flow
39
+ * and the ghost lands exactly where the caret is — no measuring, and
40
+ * nothing to drift when the font or padding changes.
41
+ *
42
+ * The wrapper exists so `inset: 0` means the input's box rather than
43
+ * the container's, which would be off by the padding and by any
44
+ * start adornment.
45
+ *
46
+ * Branching on `ghost !== undefined` rather than on the string being
47
+ * non-empty is load-bearing: a suggestion appears and disappears as
48
+ * you type, and switching JSX shape underneath a live field makes
49
+ * React unmount and remount the input — which drops focus, the
50
+ * caret and any IME composition mid-word. Pass `ghost=''` for "no
51
+ * suggestion right now" and the element stays put.
52
+ */
53
+ jsxs("span", { className: inputStyles['ghost-wrap'], children: [ghost ? (jsxs("span", { "aria-hidden": 'true', className: inputStyles['ghost'], children: [jsx("span", { className: inputStyles['ghost-typed'], children: String(rest.value ?? '') }), ghost] })) : null, jsx("input", { "data-slot": 'input-field', id: inputId, className: cn(inputStyles['input-field'], ghost && inputStyles['input-field--ghosted']), "aria-invalid": error ? 'true' : undefined, "aria-describedby": helperId, "aria-autocomplete": 'inline', onFocus: handleFocus, onBlur: handleBlur, ref: ref, type: type, ...rest })] })) : (jsx("input", { "data-slot": 'input-field', id: inputId, className: inputStyles['input-field'], "aria-invalid": error ? 'true' : undefined, "aria-describedby": helperId, onFocus: handleFocus, onBlur: handleBlur, ref: ref, type: type, ...rest })), endAdornment && (jsx("span", { "data-slot": 'input-end-adornment', className: inputStyles['adornment'], children: endAdornment }))] }), helperText && (jsx(Typography, { "data-slot": 'input-helper-text', id: helperId, variant: 'caption', className: inputStyles['helper-text'], children: helperText }))] }));
36
54
  });
37
55
  Input.displayName = 'Input';
38
56
 
@@ -1 +1 @@
1
- {"version":3,"file":"input.js","sources":["../../../src/form/Input/input.tsx"],"sourcesContent":["import { Label } from '@constellation/form/Label';\nimport { useBreakpoint } from '@constellation/hooks/use-mobile';\nimport { Typography } from '@constellation/typography/Typography';\nimport cn from 'clsx';\nimport * as React from 'react';\nimport s from './input.module.scss';\n\n// Define the possible size variants\ntype InputSize = 'sm' | 'md' | 'lg';\n\ntype InputType = React.InputHTMLAttributes<HTMLInputElement>['type'] | 'textarea';\n\nexport interface InputBaseProps {\n label?: string;\n sizeVariant?: InputSize;\n error?: boolean;\n helperText?: string;\n startAdornment?: React.ReactNode;\n endAdornment?: React.ReactNode;\n}\n\ntype InputFieldProps = InputBaseProps &\n React.InputHTMLAttributes<HTMLInputElement> & {\n type?: Exclude<InputType, 'textarea'>;\n rows?: never;\n };\n\ntype TextAreaProps = InputBaseProps &\n React.TextareaHTMLAttributes<HTMLTextAreaElement> & {\n type: 'textarea';\n rows?: number;\n };\n\n// Define the component's prop interface\ntype InputProps = InputFieldProps | TextAreaProps;\n\n// The Custom Input Component\nconst Input = React.forwardRef<HTMLInputElement | HTMLTextAreaElement, InputProps>(\n (\n {\n label,\n sizeVariant,\n error = false,\n helperText,\n startAdornment,\n endAdornment,\n id,\n type = 'text',\n rows,\n onFocus,\n onBlur,\n ...rest\n },\n ref,\n ) => {\n const { isBelow } = useBreakpoint();\n\n /*\n * Compose rather than let the caller's handler win.\n *\n * These used to be set before `{...rest}` spread over them, so any consumer\n * passing `onFocus` — to select-all on entry, say — silently replaced the\n * one driving the floating label, and the label stopped animating with no\n * error to point at it.\n */\n const handleFocus = (event: React.FocusEvent<HTMLInputElement & HTMLTextAreaElement>) => {\n setIsFocused(true);\n onFocus?.(event);\n };\n const handleBlur = (event: React.FocusEvent<HTMLInputElement & HTMLTextAreaElement>) => {\n setIsFocused(false);\n onBlur?.(event);\n };\n const generatedId = React.useId();\n const inputId = id ?? generatedId;\n const helperId = helperText ? `${inputId}-helper` : undefined;\n const resolvedSize =\n sizeVariant === 'md' && isBelow(900) ? 'sm' : (sizeVariant ?? (isBelow(900) ? 'sm' : 'md'));\n const isTextArea = type === 'textarea';\n const [isFocused, setIsFocused] = React.useState(false);\n\n const containerClasses = cn(\n s.container,\n s[resolvedSize],\n { [s.error]: error },\n { [s.disabled]: rest.disabled },\n { [s.placeholder]: rest.placeholder },\n { [s['is-focused']]: isFocused },\n { [s['has-value']]: rest.value },\n );\n\n return (\n <div data-slot={'input'} data-constellation-field className={containerClasses}>\n <div className={cn(s['input-container'], isTextArea && s['textarea-container'])}>\n {/* Start Adornment */}\n {startAdornment && (\n <span data-slot={'input-start-adornment'} className={s['adornment']}>\n {startAdornment}\n </span>\n )}\n\n <div className={s['label-container']}>\n <Label htmlFor={inputId}>\n {label}\n {(rest['aria-required'] || rest.required) && <span className={s.required}>*</span>}\n </Label>\n </div>\n {isTextArea ? (\n <textarea\n data-slot={'input-field'}\n id={inputId}\n className={s['input-field']}\n aria-invalid={error ? 'true' : undefined}\n aria-describedby={helperId}\n onFocus={handleFocus}\n onBlur={handleBlur}\n ref={ref as React.Ref<HTMLTextAreaElement>}\n rows={rows}\n {...(rest as React.TextareaHTMLAttributes<HTMLTextAreaElement>)}\n />\n ) : (\n <input\n data-slot={'input-field'}\n id={inputId}\n className={s['input-field']}\n aria-invalid={error ? 'true' : undefined}\n aria-describedby={helperId}\n onFocus={handleFocus}\n onBlur={handleBlur}\n ref={ref as React.Ref<HTMLInputElement>}\n type={type}\n {...(rest as React.InputHTMLAttributes<HTMLInputElement>)}\n />\n )}\n\n {/* End Adornment */}\n {endAdornment && (\n <span data-slot={'input-end-adornment'} className={s['adornment']}>\n {endAdornment}\n </span>\n )}\n </div>\n\n {/* Helper Text */}\n {helperText && (\n <Typography\n data-slot={'input-helper-text'}\n id={helperId}\n variant={'caption'}\n className={s['helper-text']}\n >\n {helperText}\n </Typography>\n )}\n </div>\n );\n },\n);\n\nInput.displayName = 'Input';\n\nexport { Input };\n"],"names":["s","_jsxs","_jsx"],"mappings":"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"}
1
+ {"version":3,"file":"input.js","sources":["../../../src/form/Input/input.tsx"],"sourcesContent":["import { Label } from '@constellation/form/Label';\nimport { useBreakpoint } from '@constellation/hooks/use-mobile';\nimport { Typography } from '@constellation/typography/Typography';\nimport cn from 'clsx';\nimport * as React from 'react';\nimport s from './input.module.scss';\n\n// Define the possible size variants\ntype InputSize = 'sm' | 'md' | 'lg';\n\ntype InputType = React.InputHTMLAttributes<HTMLInputElement>['type'] | 'textarea';\n\nexport interface InputBaseProps {\n label?: string;\n sizeVariant?: InputSize;\n error?: boolean;\n helperText?: string;\n startAdornment?: React.ReactNode;\n endAdornment?: React.ReactNode;\n /**\n * Inline completion drawn behind the caret — the TAIL only, not the whole\n * word. `value='Avo'` with `ghost='cado'` reads as \"Avocado\", the suggestion\n * dimmed.\n *\n * The component owns the alignment; you own the policy. What to suggest and\n * which key accepts it are decisions about your data and your users (a phone\n * has a spacebar under the thumb and no Tab), so they stay with the caller.\n * Accept by setting `value` to the completed string in your own `onKeyDown`.\n *\n * Pass `''` (not `undefined`) for \"nothing to suggest right now\": the\n * element structure stays stable, so the field is never remounted mid-word.\n *\n * Ignored for `type='textarea'` — a ghost cannot follow a caret across\n * wrapped lines without measuring, which is a different component.\n */\n ghost?: string;\n}\n\ntype InputFieldProps = InputBaseProps &\n React.InputHTMLAttributes<HTMLInputElement> & {\n type?: Exclude<InputType, 'textarea'>;\n rows?: never;\n };\n\ntype TextAreaProps = InputBaseProps &\n React.TextareaHTMLAttributes<HTMLTextAreaElement> & {\n type: 'textarea';\n rows?: number;\n };\n\n// Define the component's prop interface\ntype InputProps = InputFieldProps | TextAreaProps;\n\n// The Custom Input Component\nconst Input = React.forwardRef<HTMLInputElement | HTMLTextAreaElement, InputProps>(\n (\n {\n label,\n sizeVariant,\n error = false,\n helperText,\n startAdornment,\n endAdornment,\n id,\n type = 'text',\n rows,\n ghost,\n onFocus,\n onBlur,\n ...rest\n },\n ref,\n ) => {\n const { isBelow } = useBreakpoint();\n\n /*\n * Compose rather than let the caller's handler win.\n *\n * These used to be set before `{...rest}` spread over them, so any consumer\n * passing `onFocus` — to select-all on entry, say — silently replaced the\n * one driving the floating label, and the label stopped animating with no\n * error to point at it.\n */\n const handleFocus = (event: React.FocusEvent<HTMLInputElement & HTMLTextAreaElement>) => {\n setIsFocused(true);\n onFocus?.(event);\n };\n const handleBlur = (event: React.FocusEvent<HTMLInputElement & HTMLTextAreaElement>) => {\n setIsFocused(false);\n onBlur?.(event);\n };\n const generatedId = React.useId();\n const inputId = id ?? generatedId;\n const helperId = helperText ? `${inputId}-helper` : undefined;\n const resolvedSize =\n sizeVariant === 'md' && isBelow(900) ? 'sm' : (sizeVariant ?? (isBelow(900) ? 'sm' : 'md'));\n const isTextArea = type === 'textarea';\n const [isFocused, setIsFocused] = React.useState(false);\n\n const containerClasses = cn(\n s.container,\n s[resolvedSize],\n { [s.error]: error },\n { [s.disabled]: rest.disabled },\n { [s.placeholder]: rest.placeholder },\n { [s['is-focused']]: isFocused },\n { [s['has-value']]: rest.value },\n );\n\n return (\n <div data-slot={'input'} data-constellation-field className={containerClasses}>\n <div className={cn(s['input-container'], isTextArea && s['textarea-container'])}>\n {/* Start Adornment */}\n {startAdornment && (\n <span data-slot={'input-start-adornment'} className={s['adornment']}>\n {startAdornment}\n </span>\n )}\n\n <div className={s['label-container']}>\n <Label htmlFor={inputId}>\n {label}\n {(rest['aria-required'] || rest.required) && <span className={s.required}>*</span>}\n </Label>\n </div>\n {isTextArea ? (\n <textarea\n data-slot={'input-field'}\n id={inputId}\n className={s['input-field']}\n aria-invalid={error ? 'true' : undefined}\n aria-describedby={helperId}\n onFocus={handleFocus}\n onBlur={handleBlur}\n ref={ref as React.Ref<HTMLTextAreaElement>}\n rows={rows}\n {...(rest as React.TextareaHTMLAttributes<HTMLTextAreaElement>)}\n />\n ) : ghost !== undefined ? (\n /*\n * The ghost is drawn by re-rendering the typed value INVISIBLY and\n * letting the suggestion follow it, so the two share one text flow\n * and the ghost lands exactly where the caret is — no measuring, and\n * nothing to drift when the font or padding changes.\n *\n * The wrapper exists so `inset: 0` means the input's box rather than\n * the container's, which would be off by the padding and by any\n * start adornment.\n *\n * Branching on `ghost !== undefined` rather than on the string being\n * non-empty is load-bearing: a suggestion appears and disappears as\n * you type, and switching JSX shape underneath a live field makes\n * React unmount and remount the input — which drops focus, the\n * caret and any IME composition mid-word. Pass `ghost=''` for \"no\n * suggestion right now\" and the element stays put.\n */\n <span className={s['ghost-wrap']}>\n {ghost ? (\n <span aria-hidden={'true'} className={s['ghost']}>\n <span className={s['ghost-typed']}>{String(rest.value ?? '')}</span>\n {ghost}\n </span>\n ) : null}\n <input\n data-slot={'input-field'}\n id={inputId}\n className={cn(s['input-field'], ghost && s['input-field--ghosted'])}\n aria-invalid={error ? 'true' : undefined}\n aria-describedby={helperId}\n aria-autocomplete={'inline'}\n onFocus={handleFocus}\n onBlur={handleBlur}\n ref={ref as React.Ref<HTMLInputElement>}\n type={type}\n {...(rest as React.InputHTMLAttributes<HTMLInputElement>)}\n />\n </span>\n ) : (\n <input\n data-slot={'input-field'}\n id={inputId}\n className={s['input-field']}\n aria-invalid={error ? 'true' : undefined}\n aria-describedby={helperId}\n onFocus={handleFocus}\n onBlur={handleBlur}\n ref={ref as React.Ref<HTMLInputElement>}\n type={type}\n {...(rest as React.InputHTMLAttributes<HTMLInputElement>)}\n />\n )}\n\n {/* End Adornment */}\n {endAdornment && (\n <span data-slot={'input-end-adornment'} className={s['adornment']}>\n {endAdornment}\n </span>\n )}\n </div>\n\n {/* Helper Text */}\n {helperText && (\n <Typography\n data-slot={'input-helper-text'}\n id={helperId}\n variant={'caption'}\n className={s['helper-text']}\n >\n {helperText}\n </Typography>\n )}\n </div>\n );\n },\n);\n\nInput.displayName = 'Input';\n\nexport { Input };\n"],"names":["s","_jsxs","_jsx"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import './input.css';
2
2
 
3
- var inputStyles = {"container":"input-module_container__bycn1","label-container":"input-module_label-container__SngtG","required":"input-module_required__J1bMP","input-container":"input-module_input-container__nw0Oc","adornment":"input-module_adornment__cO4v1","textarea-container":"input-module_textarea-container__cc9-3","helper-text":"input-module_helper-text__DvzFI","is-focused":"input-module_is-focused__08nzj","error":"input-module_error__ftn_q","disabled":"input-module_disabled__9RjjE","sm":"input-module_sm__AtYYB","placeholder":"input-module_placeholder__I29pr","has-value":"input-module_has-value__juKDe","md":"input-module_md__nPnVp","lg":"input-module_lg__dC2Tp"};
3
+ var inputStyles = {"container":"input-module_container__bycn1","label-container":"input-module_label-container__SngtG","required":"input-module_required__J1bMP","input-container":"input-module_input-container__nw0Oc","ghost-wrap":"input-module_ghost-wrap__pHzia","ghost":"input-module_ghost__yVtI-","ghost-typed":"input-module_ghost-typed__r9NZN","adornment":"input-module_adornment__cO4v1","textarea-container":"input-module_textarea-container__cc9-3","helper-text":"input-module_helper-text__DvzFI","is-focused":"input-module_is-focused__08nzj","error":"input-module_error__ftn_q","disabled":"input-module_disabled__9RjjE","sm":"input-module_sm__AtYYB","placeholder":"input-module_placeholder__I29pr","has-value":"input-module_has-value__juKDe","md":"input-module_md__nPnVp","lg":"input-module_lg__dC2Tp"};
4
4
 
5
5
  export { inputStyles as default };
6
6
  //# sourceMappingURL=input.module.scss.js.map
@@ -204,6 +204,15 @@
204
204
  width: 0.875rem;
205
205
  }
206
206
 
207
+ .select-module_group-label__J50K8 {
208
+ color: var(--text-secondary);
209
+ font-size: 0.68rem;
210
+ font-weight: 600;
211
+ letter-spacing: 0.06em;
212
+ padding: 0.4rem 0.55rem 0.2rem;
213
+ text-transform: uppercase;
214
+ }
215
+
207
216
  .select-module_separator__aPMWg {
208
217
  background-color: var(--divider);
209
218
  height: 1px;
@@ -1,7 +1,17 @@
1
1
  import { type SelectContentProps, type SelectFieldProps, type SelectProps } from '@constellation/types';
2
2
  import * as React from 'react';
3
3
  declare function Select({ open: openProp, defaultOpen, onOpenChange, value: valueProp, defaultValue, onValueChange, disabled, children, ...props }: SelectProps): React.JSX.Element;
4
- declare function SelectGroup({ ...props }: React.HTMLAttributes<HTMLDivElement>): React.JSX.Element;
4
+ /**
5
+ * A titled run of options — the `<optgroup>` of this select.
6
+ *
7
+ * The heading is presentational and never focusable: it names the run, it is
8
+ * not a thing you can pick. Labelling the group with `aria-label` rather than
9
+ * pointing at the heading keeps it out of the option list for a screen reader
10
+ * too.
11
+ */
12
+ declare function SelectGroup({ label, children, ...props }: React.HTMLAttributes<HTMLDivElement> & {
13
+ label?: React.ReactNode;
14
+ }): React.JSX.Element;
5
15
  declare function SelectValue({ children, placeholder, ...props }: React.HTMLAttributes<HTMLSpanElement> & {
6
16
  placeholder?: React.ReactNode;
7
17
  }): React.JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"select.d.ts","sourceRoot":"","sources":["../../../src/form/Select/select.tsx"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EAErB,KAAK,WAAW,EAEjB,MAAM,sBAAsB,CAAC;AAI9B,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAya/B,iBAAS,MAAM,CAAC,EACd,IAAI,EAAE,QAAQ,EACd,WAAW,EACX,YAAY,EACZ,KAAK,EAAE,SAAS,EAChB,YAAY,EACZ,aAAa,EACb,QAAgB,EAChB,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,WAAW,qBAoHb;AAED,iBAAS,WAAW,CAAC,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,qBAEtE;AAED,iBAAS,WAAW,CAAC,EACnB,QAAQ,EACR,WAAW,EACX,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,eAAe,CAAC,GAAG;IAAE,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,qBAS3E;AAED,iBAAS,aAAa,CAAC,EACrB,SAAS,EACT,QAAQ,EACR,OAAO,EACP,SAAS,EACT,IAAI,EACJ,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,qBAwD/C;AAED,iBAAS,aAAa,CAAC,EACrB,KAAe,EACf,SAAS,EACT,QAAQ,EACR,gBAA4C,EAC5C,SAAS,EACT,QAAmB,EACnB,IAAe,EACf,UAAc,EACd,GAAG,KAAK,EACT,EAAE,kBAAkB,qBA2FpB;AAED,iBAAS,UAAU,CAAC,EAClB,SAAS,EACT,QAAQ,EACR,QAAgB,EAChB,OAAO,EACP,WAAW,EACX,KAAK,EACL,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,qBA2CnE;AAED,iBAAS,eAAe,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,qBAErF;AA0lBD,iBAAS,WAAW,CAAC,KAAK,EAAE,gBAAgB,qBA8N3C;AAED,OAAO,EACL,MAAM,EACN,aAAa,EACb,WAAW,EACX,WAAW,EACX,UAAU,EACV,eAAe,EACf,aAAa,EACb,WAAW,GACZ,CAAC"}
1
+ {"version":3,"file":"select.d.ts","sourceRoot":"","sources":["../../../src/form/Select/select.tsx"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EAErB,KAAK,WAAW,EAEjB,MAAM,sBAAsB,CAAC;AAI9B,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAya/B,iBAAS,MAAM,CAAC,EACd,IAAI,EAAE,QAAQ,EACd,WAAW,EACX,YAAY,EACZ,KAAK,EAAE,SAAS,EAChB,YAAY,EACZ,aAAa,EACb,QAAgB,EAChB,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,WAAW,qBAoHb;AAED;;;;;;;GAOG;AACH,iBAAS,WAAW,CAAC,EACnB,KAAK,EACL,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,GAAG;IAAE,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,qBAgBpE;AAED,iBAAS,WAAW,CAAC,EACnB,QAAQ,EACR,WAAW,EACX,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,eAAe,CAAC,GAAG;IAAE,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,qBAS3E;AAED,iBAAS,aAAa,CAAC,EACrB,SAAS,EACT,QAAQ,EACR,OAAO,EACP,SAAS,EACT,IAAI,EACJ,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,qBAwD/C;AAED,iBAAS,aAAa,CAAC,EACrB,KAAe,EACf,SAAS,EACT,QAAQ,EACR,gBAA4C,EAC5C,SAAS,EACT,QAAmB,EACnB,IAAe,EACf,UAAc,EACd,GAAG,KAAK,EACT,EAAE,kBAAkB,qBA2FpB;AAED,iBAAS,UAAU,CAAC,EAClB,SAAS,EACT,QAAQ,EACR,QAAgB,EAChB,OAAO,EACP,WAAW,EACX,KAAK,EACL,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,qBA2CnE;AAED,iBAAS,eAAe,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,qBAErF;AA0lBD,iBAAS,WAAW,CAAC,KAAK,EAAE,gBAAgB,qBA8N3C;AAED,OAAO,EACL,MAAM,EACN,aAAa,EACb,WAAW,EACX,WAAW,EACX,UAAU,EACV,eAAe,EACf,aAAa,EACb,WAAW,GACZ,CAAC"}
@@ -342,8 +342,16 @@ function Select({ open: openProp, defaultOpen, onOpenChange, value: valueProp, d
342
342
  ]);
343
343
  return (jsx(SelectContext.Provider, { value: contextValue, children: jsx("div", { "data-slot": 'select', ...props, children: children }) }));
344
344
  }
345
- function SelectGroup({ ...props }) {
346
- return jsx("div", { "data-slot": 'select-group', ...props });
345
+ /**
346
+ * A titled run of options — the `<optgroup>` of this select.
347
+ *
348
+ * The heading is presentational and never focusable: it names the run, it is
349
+ * not a thing you can pick. Labelling the group with `aria-label` rather than
350
+ * pointing at the heading keeps it out of the option list for a screen reader
351
+ * too.
352
+ */
353
+ function SelectGroup({ label, children, ...props }) {
354
+ return (jsxs("div", { "data-slot": 'select-group', role: 'group', "aria-label": typeof label === 'string' ? label : undefined, ...props, children: [label ? (jsx("div", { "data-slot": 'select-group-label', "aria-hidden": 'true', className: s['group-label'], children: label })) : null, children] }));
347
355
  }
348
356
  function SelectValue({ children, placeholder, ...props }) {
349
357
  const context = useSelectContext('SelectValue');