elseware-ui 3.0.9 → 3.0.10

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.mjs CHANGED
@@ -9043,6 +9043,24 @@ function StarRatingInput({
9043
9043
  );
9044
9044
  }
9045
9045
  var StarRatingInput_default = StarRatingInput;
9046
+ function useClickOutside(ref, fun) {
9047
+ useEffect(() => {
9048
+ const listener = (e) => {
9049
+ if (!ref.current || ref.current.contains(e.target)) {
9050
+ return;
9051
+ }
9052
+ if (fun) {
9053
+ fun();
9054
+ }
9055
+ };
9056
+ document.addEventListener("mousedown", listener);
9057
+ document.addEventListener("touchstart", listener);
9058
+ return () => {
9059
+ document.removeEventListener("mousedown", listener);
9060
+ document.removeEventListener("touchstart", listener);
9061
+ };
9062
+ }, [ref, fun]);
9063
+ }
9046
9064
  function useResolvedSelectConfig({
9047
9065
  label,
9048
9066
  placeholder,
@@ -9062,25 +9080,65 @@ function useSelectFieldState(props) {
9062
9080
  meta
9063
9081
  };
9064
9082
  }
9083
+
9084
+ // src/components/data-entry/select/web/Select.web.styles.ts
9085
+ var webSelectTriggerClassName = "flex items-center justify-between gap-3 text-left outline-none transition-all duration-200 ease-out";
9086
+ var webSelectValueClassName = "block min-w-0 flex-1 truncate text-base font-normal text-gray-950 dark:text-gray-300";
9087
+ var webSelectPlaceholderClassName = "text-gray-500 dark:text-gray-400";
9088
+ var webSelectChevronClassName = "pointer-events-none shrink-0 text-base text-gray-500 transition-transform duration-150 ease-out dark:text-gray-400";
9089
+ var webSelectChevronOpenClassName = "rotate-180";
9090
+ var webSelectDropdownClassName = "absolute left-0 right-0 top-full z-30 mt-2 overflow-hidden rounded-md border border-gray-200 bg-white shadow-xl shadow-black/10 ring-1 ring-black/5 dark:border-eui-dark-300 dark:bg-eui-dark-500 dark:shadow-black/30 dark:ring-white/10";
9091
+ var webSelectListClassName = "max-h-[228px] overflow-y-auto py-1";
9092
+ var webSelectOptionClassName = "flex min-h-11 w-full items-center px-3 py-2 text-left text-sm font-medium text-gray-800 outline-none transition-colors duration-120 ease-out dark:text-gray-100";
9093
+ var webSelectOptionHoverClassName = "hover:bg-gray-100 focus:bg-gray-100 dark:hover:bg-eui-dark-400 dark:focus:bg-eui-dark-400";
9094
+ var webSelectOptionSelectedClassName = "bg-eui-secondary-500/10 text-eui-secondary-700 dark:bg-eui-secondary-500/15 dark:text-eui-secondary-300";
9095
+ var webSelectOptionActiveClassName = "bg-gray-100 dark:bg-eui-dark-400";
9096
+ var webSelectOptionDisabledClassName = "cursor-not-allowed opacity-45 hover:bg-transparent focus:bg-transparent dark:hover:bg-transparent dark:focus:bg-transparent";
9097
+ var webSelectOptionContentClassName = "min-w-0 flex-1 truncate";
9098
+ var webSelectEmptyClassName = "px-3 py-3 text-sm font-medium text-gray-500 dark:text-gray-400";
9099
+ function getEnabledOptionIndex(options, startIndex = 0, direction = 1) {
9100
+ if (!options.length) return -1;
9101
+ for (let offset = 0; offset < options.length; offset += 1) {
9102
+ const index3 = (startIndex + offset * direction + options.length) % options.length;
9103
+ if (!options[index3]?.disabled) {
9104
+ return index3;
9105
+ }
9106
+ }
9107
+ return -1;
9108
+ }
9065
9109
  function Select(selectProps) {
9066
9110
  const {
9111
+ activeOptionClassName,
9112
+ chevronClassName,
9067
9113
  disabled = false,
9114
+ disabledOptionClassName,
9115
+ dropdownClassName,
9116
+ emptyClassName,
9117
+ emptyMessage = "No options available",
9068
9118
  id: id2,
9069
9119
  inputClassName,
9070
9120
  label,
9071
9121
  labelClassName,
9122
+ optionClassName,
9123
+ optionContentClassName,
9072
9124
  options,
9073
9125
  placeholder,
9074
9126
  responseClassName,
9127
+ selectedOptionClassName,
9075
9128
  shape,
9076
9129
  styles,
9077
9130
  className,
9078
9131
  onBlur,
9079
9132
  onFocus,
9080
- ...props
9133
+ ..._props
9081
9134
  } = selectProps;
9082
- const { field, meta } = useSelectFieldState(selectProps);
9135
+ const rootRef = useRef(null);
9136
+ const triggerRef = useRef(null);
9137
+ const reactId = useId();
9138
+ const { field, helpers, meta } = useSelectFieldState(selectProps);
9083
9139
  const [focused, setFocused] = useState(false);
9140
+ const [open, setOpen] = useState(false);
9141
+ const [activeIndex, setActiveIndex] = useState(-1);
9084
9142
  const { label: resolvedLabel, shape: resolvedShape } = useResolvedSelectConfig({
9085
9143
  label,
9086
9144
  placeholder,
@@ -9088,48 +9146,237 @@ function Select(selectProps) {
9088
9146
  });
9089
9147
  const hasError = Boolean(meta.touched && meta.error);
9090
9148
  const inputId = id2 ?? field.name;
9091
- const handleBlur = (event) => {
9092
- setFocused(false);
9093
- field.onBlur(event);
9149
+ const listboxId = `${reactId}-${field.name}-listbox`;
9150
+ const selectedIndex = options.findIndex(
9151
+ (option) => option.value === field.value
9152
+ );
9153
+ const selectedOption = selectedIndex >= 0 ? options[selectedIndex] : null;
9154
+ const selectedOptionDisabled = Boolean(selectedOption?.disabled);
9155
+ const selectedLabel = selectedOption?.label ?? "";
9156
+ const hasValue = Boolean(selectedOption);
9157
+ const resolvedActiveIndex = activeIndex >= 0 ? activeIndex : getEnabledOptionIndex(options);
9158
+ const openOptions = useCallback(() => {
9159
+ if (disabled) return;
9160
+ const initialIndex = selectedIndex >= 0 && !selectedOptionDisabled ? selectedIndex : getEnabledOptionIndex(options);
9161
+ setFocused(true);
9162
+ setOpen(true);
9163
+ setActiveIndex(initialIndex);
9164
+ }, [disabled, options, selectedIndex, selectedOptionDisabled]);
9165
+ const closeOptions = useCallback(
9166
+ (markTouched = true, keepFocused = false) => {
9167
+ setOpen(false);
9168
+ setActiveIndex(-1);
9169
+ setFocused(keepFocused);
9170
+ if (markTouched) {
9171
+ void helpers.setTouched(true);
9172
+ }
9173
+ },
9174
+ [helpers]
9175
+ );
9176
+ useClickOutside(rootRef, () => {
9177
+ if (open) {
9178
+ closeOptions();
9179
+ }
9180
+ });
9181
+ const handleButtonFocus = (event) => {
9182
+ setFocused(true);
9183
+ onFocus?.(event);
9184
+ };
9185
+ const handleRootBlur = (event) => {
9186
+ if (event.relatedTarget instanceof Node && rootRef.current?.contains(event.relatedTarget)) {
9187
+ return;
9188
+ }
9189
+ closeOptions();
9094
9190
  onBlur?.(event);
9095
9191
  };
9096
- const handleFocus = (event) => {
9192
+ const handleToggle = () => {
9193
+ if (disabled) return;
9194
+ if (open) {
9195
+ closeOptions(true, true);
9196
+ return;
9197
+ }
9198
+ openOptions();
9199
+ };
9200
+ const handleSelect = (option) => {
9201
+ if (disabled || option.disabled) return;
9202
+ void helpers.setValue(option.value);
9203
+ void helpers.setTouched(true);
9204
+ setOpen(false);
9205
+ setActiveIndex(-1);
9097
9206
  setFocused(true);
9098
- onFocus?.(event);
9207
+ window.setTimeout(() => triggerRef.current?.focus(), 0);
9099
9208
  };
9100
- return /* @__PURE__ */ jsxs("div", { className: inputRootClassName, children: [
9101
- /* @__PURE__ */ jsx(
9102
- Field,
9209
+ const setNextActiveIndex = (direction) => {
9210
+ const nextIndex = getEnabledOptionIndex(
9211
+ options,
9212
+ resolvedActiveIndex + direction,
9213
+ direction
9214
+ );
9215
+ setActiveIndex(nextIndex);
9216
+ };
9217
+ const handleKeyDown = (event) => {
9218
+ switch (event.key) {
9219
+ case "ArrowDown":
9220
+ event.preventDefault();
9221
+ if (!open) {
9222
+ openOptions();
9223
+ return;
9224
+ }
9225
+ setNextActiveIndex(1);
9226
+ return;
9227
+ case "ArrowUp":
9228
+ event.preventDefault();
9229
+ if (!open) {
9230
+ openOptions();
9231
+ return;
9232
+ }
9233
+ setNextActiveIndex(-1);
9234
+ return;
9235
+ case "Home":
9236
+ if (open) {
9237
+ event.preventDefault();
9238
+ setActiveIndex(getEnabledOptionIndex(options));
9239
+ }
9240
+ return;
9241
+ case "End":
9242
+ if (open) {
9243
+ event.preventDefault();
9244
+ setActiveIndex(
9245
+ getEnabledOptionIndex(options, options.length - 1, -1)
9246
+ );
9247
+ }
9248
+ return;
9249
+ case "Enter":
9250
+ case " ":
9251
+ event.preventDefault();
9252
+ if (!open) {
9253
+ openOptions();
9254
+ return;
9255
+ }
9256
+ if (resolvedActiveIndex >= 0) {
9257
+ handleSelect(options[resolvedActiveIndex]);
9258
+ }
9259
+ return;
9260
+ case "Escape":
9261
+ if (open) {
9262
+ event.preventDefault();
9263
+ closeOptions(true, true);
9264
+ }
9265
+ return;
9266
+ case "Tab":
9267
+ closeOptions();
9268
+ return;
9269
+ default:
9270
+ return;
9271
+ }
9272
+ };
9273
+ return /* @__PURE__ */ jsxs("div", { ref: rootRef, className: inputRootClassName, onBlur: handleRootBlur, children: [
9274
+ /* @__PURE__ */ jsx("input", { name: field.name, type: "hidden", value: field.value ?? "" }),
9275
+ /* @__PURE__ */ jsxs(
9276
+ "button",
9103
9277
  {
9104
- ...props,
9105
- ...field,
9106
- as: "select",
9107
- disabled,
9108
- id: inputId,
9109
- onBlur: handleBlur,
9110
- onFocus: handleFocus,
9278
+ "aria-activedescendant": open && resolvedActiveIndex >= 0 ? `${listboxId}-option-${resolvedActiveIndex}` : void 0,
9279
+ "aria-controls": listboxId,
9280
+ "aria-disabled": disabled || void 0,
9281
+ "aria-expanded": open,
9282
+ "aria-haspopup": "listbox",
9283
+ "aria-invalid": hasError || void 0,
9111
9284
  className: cn(
9112
9285
  inputFrameClassName,
9113
9286
  inputControlClassName,
9114
- webInputControlClassName,
9115
- hasError ? inputFrameErrorClassName : focused ? inputFrameActiveClassName : inputFrameIdleClassName,
9287
+ webSelectTriggerClassName,
9288
+ hasError ? inputFrameErrorClassName : focused || open ? inputFrameActiveClassName : inputFrameIdleClassName,
9116
9289
  inputShapes[resolvedShape],
9117
9290
  disabled && inputFrameDisabledClassName,
9118
9291
  className,
9119
- styles,
9120
- inputClassName
9292
+ styles
9121
9293
  ),
9122
- children: options.map((option) => /* @__PURE__ */ jsx(
9123
- "option",
9124
- {
9125
- value: option.value,
9126
- disabled: option.disabled,
9127
- children: option.label
9128
- },
9129
- option.value
9130
- ))
9294
+ disabled,
9295
+ id: inputId,
9296
+ onClick: handleToggle,
9297
+ onFocus: handleButtonFocus,
9298
+ onKeyDown: handleKeyDown,
9299
+ ref: triggerRef,
9300
+ role: "combobox",
9301
+ type: "button",
9302
+ children: [
9303
+ /* @__PURE__ */ jsx(
9304
+ "span",
9305
+ {
9306
+ className: cn(
9307
+ webSelectValueClassName,
9308
+ !hasValue && webSelectPlaceholderClassName,
9309
+ inputClassName
9310
+ ),
9311
+ children: hasValue ? selectedLabel : ""
9312
+ }
9313
+ ),
9314
+ /* @__PURE__ */ jsx(
9315
+ BsChevronDown,
9316
+ {
9317
+ "aria-hidden": "true",
9318
+ className: cn(
9319
+ webSelectChevronClassName,
9320
+ open && webSelectChevronOpenClassName,
9321
+ chevronClassName
9322
+ )
9323
+ }
9324
+ )
9325
+ ]
9131
9326
  }
9132
9327
  ),
9328
+ /* @__PURE__ */ jsx(TransitionDropdown_default, { visibility: open, children: /* @__PURE__ */ jsx(
9329
+ "div",
9330
+ {
9331
+ "aria-label": resolvedLabel,
9332
+ className: cn(webSelectDropdownClassName, dropdownClassName),
9333
+ id: listboxId,
9334
+ role: "listbox",
9335
+ children: /* @__PURE__ */ jsx("div", { className: webSelectListClassName, children: options.length > 0 ? options.map((option, index3) => {
9336
+ const selected = option.value === field.value;
9337
+ const active = index3 === resolvedActiveIndex;
9338
+ return /* @__PURE__ */ jsx(
9339
+ "button",
9340
+ {
9341
+ "aria-disabled": option.disabled || void 0,
9342
+ "aria-selected": selected,
9343
+ className: cn(
9344
+ webSelectOptionClassName,
9345
+ !option.disabled && webSelectOptionHoverClassName,
9346
+ selected && webSelectOptionSelectedClassName,
9347
+ active && webSelectOptionActiveClassName,
9348
+ option.disabled && webSelectOptionDisabledClassName,
9349
+ selected && selectedOptionClassName,
9350
+ active && activeOptionClassName,
9351
+ option.disabled && disabledOptionClassName,
9352
+ optionClassName
9353
+ ),
9354
+ disabled: option.disabled,
9355
+ id: `${listboxId}-option-${index3}`,
9356
+ onClick: () => handleSelect(option),
9357
+ onMouseEnter: () => {
9358
+ if (!option.disabled) {
9359
+ setActiveIndex(index3);
9360
+ }
9361
+ },
9362
+ role: "option",
9363
+ type: "button",
9364
+ children: /* @__PURE__ */ jsx(
9365
+ "span",
9366
+ {
9367
+ className: cn(
9368
+ webSelectOptionContentClassName,
9369
+ optionContentClassName
9370
+ ),
9371
+ children: option.label
9372
+ }
9373
+ )
9374
+ },
9375
+ option.value
9376
+ );
9377
+ }) : /* @__PURE__ */ jsx("div", { className: cn(webSelectEmptyClassName, emptyClassName), children: emptyMessage }) })
9378
+ }
9379
+ ) }),
9133
9380
  /* @__PURE__ */ jsx(
9134
9381
  InputLabel,
9135
9382
  {
@@ -9979,24 +10226,6 @@ function HeaderNav({ data = [], styles }) {
9979
10226
  );
9980
10227
  }
9981
10228
  var HeaderNav_default = HeaderNav;
9982
- function useClickOutside(ref, fun) {
9983
- useEffect(() => {
9984
- const listener = (e) => {
9985
- if (!ref.current || ref.current.contains(e.target)) {
9986
- return;
9987
- }
9988
- if (fun) {
9989
- fun();
9990
- }
9991
- };
9992
- document.addEventListener("mousedown", listener);
9993
- document.addEventListener("touchstart", listener);
9994
- return () => {
9995
- document.removeEventListener("mousedown", listener);
9996
- document.removeEventListener("touchstart", listener);
9997
- };
9998
- }, [ref, fun]);
9999
- }
10000
10229
  var HeaderNavItemContext = ({
10001
10230
  icon,
10002
10231
  name: name2,