@camstack/ui-library 1.2.278 → 1.2.279

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/index.cjs CHANGED
@@ -10957,6 +10957,43 @@ var PasswordInput = (0, react$1.forwardRef)(({ value, onValueChange, shown, onTo
10957
10957
  });
10958
10958
  PasswordInput.displayName = "PasswordInput";
10959
10959
  //#endregion
10960
+ //#region src/primitives/select.tsx
10961
+ /**
10962
+ * A native `<select>` styled to match the rest of the field set.
10963
+ *
10964
+ * `appearance-none` plus an explicit `bg-surface` / `text-foreground` is what
10965
+ * makes it match — and it is also what USED to make a disabled one a lie. A
10966
+ * browser greys a disabled control by rendering its own background and text
10967
+ * colour; all three of those are overridden here, so a `disabled` dropdown
10968
+ * looked exactly like a live one and simply ignored the click. That is the
10969
+ * whole of the "the language selector does not open" report of 2026-08-15:
10970
+ * the AI section's switch was off, every control under it was correctly inert,
10971
+ * and nothing on screen said so.
10972
+ *
10973
+ * `disabled:` classes belong HERE and not on each call site: there are dozens
10974
+ * of `<Select disabled>` in this app and the one that gets forgotten is the one
10975
+ * that generates the ticket. Guarded by `disabled-affordance.test.tsx`.
10976
+ */
10977
+ var Select = (0, react$1.forwardRef)(({ className, options, disabled, ...props }, ref) => {
10978
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
10979
+ className: "relative w-full",
10980
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
10981
+ ref,
10982
+ disabled,
10983
+ className: cn("h-7 w-full px-2.5 text-xs bg-surface border border-border rounded-md text-foreground appearance-none pr-7 focus:outline-none focus:ring-1 focus:ring-primary", "disabled:opacity-50 disabled:cursor-not-allowed", className),
10984
+ ...props,
10985
+ children: options.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
10986
+ value: option.value,
10987
+ children: option.label
10988
+ }, option.value))
10989
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
10990
+ className: cn("absolute right-2 top-1/2 -translate-y-1/2 pointer-events-none text-foreground-muted", disabled === true ? "opacity-50" : ""),
10991
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronDown, { className: "h-3.5 w-3.5" })
10992
+ })]
10993
+ });
10994
+ });
10995
+ Select.displayName = "Select";
10996
+ //#endregion
10960
10997
  //#region src/composites/config-secret-field.tsx
10961
10998
  /**
10962
10999
  * A keychain-stored secret in a settings form (D787, D789) — drawn as ONE
@@ -21313,43 +21350,6 @@ var Button = (0, react$1.forwardRef)(({ className, variant, size, ...props }, re
21313
21350
  });
21314
21351
  Button.displayName = "Button";
21315
21352
  //#endregion
21316
- //#region src/primitives/select.tsx
21317
- /**
21318
- * A native `<select>` styled to match the rest of the field set.
21319
- *
21320
- * `appearance-none` plus an explicit `bg-surface` / `text-foreground` is what
21321
- * makes it match — and it is also what USED to make a disabled one a lie. A
21322
- * browser greys a disabled control by rendering its own background and text
21323
- * colour; all three of those are overridden here, so a `disabled` dropdown
21324
- * looked exactly like a live one and simply ignored the click. That is the
21325
- * whole of the "the language selector does not open" report of 2026-08-15:
21326
- * the AI section's switch was off, every control under it was correctly inert,
21327
- * and nothing on screen said so.
21328
- *
21329
- * `disabled:` classes belong HERE and not on each call site: there are dozens
21330
- * of `<Select disabled>` in this app and the one that gets forgotten is the one
21331
- * that generates the ticket. Guarded by `disabled-affordance.test.tsx`.
21332
- */
21333
- var Select = (0, react$1.forwardRef)(({ className, options, disabled, ...props }, ref) => {
21334
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
21335
- className: "relative w-full",
21336
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
21337
- ref,
21338
- disabled,
21339
- className: cn("h-7 w-full px-2.5 text-xs bg-surface border border-border rounded-md text-foreground appearance-none pr-7 focus:outline-none focus:ring-1 focus:ring-primary", "disabled:opacity-50 disabled:cursor-not-allowed", className),
21340
- ...props,
21341
- children: options.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
21342
- value: option.value,
21343
- children: option.label
21344
- }, option.value))
21345
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
21346
- className: cn("absolute right-2 top-1/2 -translate-y-1/2 pointer-events-none text-foreground-muted", disabled === true ? "opacity-50" : ""),
21347
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronDown, { className: "h-3.5 w-3.5" })
21348
- })]
21349
- });
21350
- });
21351
- Select.displayName = "Select";
21352
- //#endregion
21353
21353
  //#region src/primitives/skeleton.tsx
21354
21354
  var Skeleton = (0, react$1.forwardRef)(({ className, ...props }, ref) => {
21355
21355
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -28322,7 +28322,7 @@ function TimezoneSelector({ value, onChange, disabled }) {
28322
28322
  var INPUT_CLASS = "w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-xs text-foreground focus:border-primary focus:ring-1 focus:ring-primary/30 outline-none disabled:opacity-50 disabled:cursor-not-allowed";
28323
28323
  var LABEL_CLASS$1 = "block text-[11px] font-medium text-foreground mb-1 break-words";
28324
28324
  var DESC_CLASS = "text-[10px] text-foreground-subtle mt-0.5 break-words";
28325
- function FieldWrapper({ label, description, required, span, children, translationFn }) {
28325
+ function FieldWrapper({ label, description, required, span, htmlFor, children, translationFn }) {
28326
28326
  const colSpanClass = span === 2 ? "col-span-1 @[480px]:col-span-2" : span === 3 ? "col-span-1 @[480px]:col-span-2 @[880px]:col-span-3" : span === 4 ? "col-span-1 @[480px]:col-span-2 @[1140px]:col-span-4" : "col-span-1";
28327
28327
  const resolvedLabel = resolveLabel(label, translationFn);
28328
28328
  const resolvedDescription = resolveLabel(description, translationFn);
@@ -28332,6 +28332,7 @@ function FieldWrapper({ label, description, required, span, children, translatio
28332
28332
  children: [
28333
28333
  hasLabel && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
28334
28334
  className: LABEL_CLASS$1,
28335
+ ...htmlFor !== void 0 ? { htmlFor } : {},
28335
28336
  children: [resolvedLabel, required && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
28336
28337
  className: "text-danger ml-0.5",
28337
28338
  children: "*"
@@ -28500,24 +28501,27 @@ function BooleanField({ field, value, onChange, disabled, translationFn }) {
28500
28501
  }
28501
28502
  function SelectField({ field, value, onChange, disabled, translationFn }) {
28502
28503
  const hasEmptyOption = field.options.some((o) => o.value === "");
28504
+ const options = [...!field.required && !hasEmptyOption ? [{
28505
+ value: "",
28506
+ label: "— Select —"
28507
+ }] : [], ...field.options.map((opt) => ({
28508
+ value: opt.value,
28509
+ label: opt.label
28510
+ }))];
28511
+ const controlId = `config-select-${field.key}`;
28503
28512
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FieldWrapper, {
28504
28513
  label: field.label,
28505
28514
  description: field.description,
28506
28515
  required: field.required,
28507
28516
  span: field.span,
28517
+ htmlFor: controlId,
28508
28518
  translationFn,
28509
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
28510
- className: INPUT_CLASS,
28519
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Select, {
28520
+ id: controlId,
28521
+ options,
28511
28522
  value: value === void 0 || value === null ? "" : String(value),
28512
28523
  disabled: disabled || field.disabled,
28513
- onChange: (e) => onChange(e.target.value),
28514
- children: [!field.required && !hasEmptyOption && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
28515
- value: "",
28516
- children: "— Select —"
28517
- }), field.options.map((opt) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
28518
- value: opt.value,
28519
- children: opt.label
28520
- }, opt.value))]
28524
+ onChange: (e) => onChange(e.target.value)
28521
28525
  })
28522
28526
  });
28523
28527
  }
package/dist/index.js CHANGED
@@ -10933,6 +10933,43 @@ var PasswordInput = forwardRef(({ value, onValueChange, shown, onToggleShown, bu
10933
10933
  });
10934
10934
  PasswordInput.displayName = "PasswordInput";
10935
10935
  //#endregion
10936
+ //#region src/primitives/select.tsx
10937
+ /**
10938
+ * A native `<select>` styled to match the rest of the field set.
10939
+ *
10940
+ * `appearance-none` plus an explicit `bg-surface` / `text-foreground` is what
10941
+ * makes it match — and it is also what USED to make a disabled one a lie. A
10942
+ * browser greys a disabled control by rendering its own background and text
10943
+ * colour; all three of those are overridden here, so a `disabled` dropdown
10944
+ * looked exactly like a live one and simply ignored the click. That is the
10945
+ * whole of the "the language selector does not open" report of 2026-08-15:
10946
+ * the AI section's switch was off, every control under it was correctly inert,
10947
+ * and nothing on screen said so.
10948
+ *
10949
+ * `disabled:` classes belong HERE and not on each call site: there are dozens
10950
+ * of `<Select disabled>` in this app and the one that gets forgotten is the one
10951
+ * that generates the ticket. Guarded by `disabled-affordance.test.tsx`.
10952
+ */
10953
+ var Select = forwardRef(({ className, options, disabled, ...props }, ref) => {
10954
+ return /* @__PURE__ */ jsxs("div", {
10955
+ className: "relative w-full",
10956
+ children: [/* @__PURE__ */ jsx("select", {
10957
+ ref,
10958
+ disabled,
10959
+ className: cn("h-7 w-full px-2.5 text-xs bg-surface border border-border rounded-md text-foreground appearance-none pr-7 focus:outline-none focus:ring-1 focus:ring-primary", "disabled:opacity-50 disabled:cursor-not-allowed", className),
10960
+ ...props,
10961
+ children: options.map((option) => /* @__PURE__ */ jsx("option", {
10962
+ value: option.value,
10963
+ children: option.label
10964
+ }, option.value))
10965
+ }), /* @__PURE__ */ jsx("div", {
10966
+ className: cn("absolute right-2 top-1/2 -translate-y-1/2 pointer-events-none text-foreground-muted", disabled === true ? "opacity-50" : ""),
10967
+ children: /* @__PURE__ */ jsx(ChevronDown, { className: "h-3.5 w-3.5" })
10968
+ })]
10969
+ });
10970
+ });
10971
+ Select.displayName = "Select";
10972
+ //#endregion
10936
10973
  //#region src/composites/config-secret-field.tsx
10937
10974
  /**
10938
10975
  * A keychain-stored secret in a settings form (D787, D789) — drawn as ONE
@@ -21289,43 +21326,6 @@ var Button = forwardRef(({ className, variant, size, ...props }, ref) => {
21289
21326
  });
21290
21327
  Button.displayName = "Button";
21291
21328
  //#endregion
21292
- //#region src/primitives/select.tsx
21293
- /**
21294
- * A native `<select>` styled to match the rest of the field set.
21295
- *
21296
- * `appearance-none` plus an explicit `bg-surface` / `text-foreground` is what
21297
- * makes it match — and it is also what USED to make a disabled one a lie. A
21298
- * browser greys a disabled control by rendering its own background and text
21299
- * colour; all three of those are overridden here, so a `disabled` dropdown
21300
- * looked exactly like a live one and simply ignored the click. That is the
21301
- * whole of the "the language selector does not open" report of 2026-08-15:
21302
- * the AI section's switch was off, every control under it was correctly inert,
21303
- * and nothing on screen said so.
21304
- *
21305
- * `disabled:` classes belong HERE and not on each call site: there are dozens
21306
- * of `<Select disabled>` in this app and the one that gets forgotten is the one
21307
- * that generates the ticket. Guarded by `disabled-affordance.test.tsx`.
21308
- */
21309
- var Select = forwardRef(({ className, options, disabled, ...props }, ref) => {
21310
- return /* @__PURE__ */ jsxs("div", {
21311
- className: "relative w-full",
21312
- children: [/* @__PURE__ */ jsx("select", {
21313
- ref,
21314
- disabled,
21315
- className: cn("h-7 w-full px-2.5 text-xs bg-surface border border-border rounded-md text-foreground appearance-none pr-7 focus:outline-none focus:ring-1 focus:ring-primary", "disabled:opacity-50 disabled:cursor-not-allowed", className),
21316
- ...props,
21317
- children: options.map((option) => /* @__PURE__ */ jsx("option", {
21318
- value: option.value,
21319
- children: option.label
21320
- }, option.value))
21321
- }), /* @__PURE__ */ jsx("div", {
21322
- className: cn("absolute right-2 top-1/2 -translate-y-1/2 pointer-events-none text-foreground-muted", disabled === true ? "opacity-50" : ""),
21323
- children: /* @__PURE__ */ jsx(ChevronDown, { className: "h-3.5 w-3.5" })
21324
- })]
21325
- });
21326
- });
21327
- Select.displayName = "Select";
21328
- //#endregion
21329
21329
  //#region src/primitives/skeleton.tsx
21330
21330
  var Skeleton = forwardRef(({ className, ...props }, ref) => {
21331
21331
  return /* @__PURE__ */ jsx("div", {
@@ -28298,7 +28298,7 @@ function TimezoneSelector({ value, onChange, disabled }) {
28298
28298
  var INPUT_CLASS = "w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-xs text-foreground focus:border-primary focus:ring-1 focus:ring-primary/30 outline-none disabled:opacity-50 disabled:cursor-not-allowed";
28299
28299
  var LABEL_CLASS$1 = "block text-[11px] font-medium text-foreground mb-1 break-words";
28300
28300
  var DESC_CLASS = "text-[10px] text-foreground-subtle mt-0.5 break-words";
28301
- function FieldWrapper({ label, description, required, span, children, translationFn }) {
28301
+ function FieldWrapper({ label, description, required, span, htmlFor, children, translationFn }) {
28302
28302
  const colSpanClass = span === 2 ? "col-span-1 @[480px]:col-span-2" : span === 3 ? "col-span-1 @[480px]:col-span-2 @[880px]:col-span-3" : span === 4 ? "col-span-1 @[480px]:col-span-2 @[1140px]:col-span-4" : "col-span-1";
28303
28303
  const resolvedLabel = resolveLabel(label, translationFn);
28304
28304
  const resolvedDescription = resolveLabel(description, translationFn);
@@ -28308,6 +28308,7 @@ function FieldWrapper({ label, description, required, span, children, translatio
28308
28308
  children: [
28309
28309
  hasLabel && /* @__PURE__ */ jsxs("label", {
28310
28310
  className: LABEL_CLASS$1,
28311
+ ...htmlFor !== void 0 ? { htmlFor } : {},
28311
28312
  children: [resolvedLabel, required && /* @__PURE__ */ jsx("span", {
28312
28313
  className: "text-danger ml-0.5",
28313
28314
  children: "*"
@@ -28476,24 +28477,27 @@ function BooleanField({ field, value, onChange, disabled, translationFn }) {
28476
28477
  }
28477
28478
  function SelectField({ field, value, onChange, disabled, translationFn }) {
28478
28479
  const hasEmptyOption = field.options.some((o) => o.value === "");
28480
+ const options = [...!field.required && !hasEmptyOption ? [{
28481
+ value: "",
28482
+ label: "— Select —"
28483
+ }] : [], ...field.options.map((opt) => ({
28484
+ value: opt.value,
28485
+ label: opt.label
28486
+ }))];
28487
+ const controlId = `config-select-${field.key}`;
28479
28488
  return /* @__PURE__ */ jsx(FieldWrapper, {
28480
28489
  label: field.label,
28481
28490
  description: field.description,
28482
28491
  required: field.required,
28483
28492
  span: field.span,
28493
+ htmlFor: controlId,
28484
28494
  translationFn,
28485
- children: /* @__PURE__ */ jsxs("select", {
28486
- className: INPUT_CLASS,
28495
+ children: /* @__PURE__ */ jsx(Select, {
28496
+ id: controlId,
28497
+ options,
28487
28498
  value: value === void 0 || value === null ? "" : String(value),
28488
28499
  disabled: disabled || field.disabled,
28489
- onChange: (e) => onChange(e.target.value),
28490
- children: [!field.required && !hasEmptyOption && /* @__PURE__ */ jsx("option", {
28491
- value: "",
28492
- children: "— Select —"
28493
- }), field.options.map((opt) => /* @__PURE__ */ jsx("option", {
28494
- value: opt.value,
28495
- children: opt.label
28496
- }, opt.value))]
28500
+ onChange: (e) => onChange(e.target.value)
28497
28501
  })
28498
28502
  });
28499
28503
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/ui-library",
3
- "version": "1.2.278",
3
+ "version": "1.2.279",
4
4
  "type": "module",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",