@timeax/form-palette 0.0.25 → 0.0.27

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
@@ -15213,6 +15213,65 @@ var ToggleVariantModule = {
15213
15213
  }
15214
15214
  };
15215
15215
  var toggle_default2 = ToggleVariantModule;
15216
+
15217
+ // src/lib/group-layout.ts
15218
+ function buildGroupLayoutClasses(opts) {
15219
+ const {
15220
+ layout,
15221
+ columns,
15222
+ itemGapPx,
15223
+ groupClassName,
15224
+ className,
15225
+ optionClassName,
15226
+ labelClassName,
15227
+ descriptionClassName,
15228
+ densityPaddingClass,
15229
+ labelTextSizeClass,
15230
+ descriptionTextSizeClass
15231
+ } = opts;
15232
+ let groupStyle;
15233
+ if (!itemGapPx) {
15234
+ if (layout === "grid") {
15235
+ groupStyle = {
15236
+ gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`
15237
+ };
15238
+ }
15239
+ } else if (layout === "list") {
15240
+ groupStyle = { rowGap: itemGapPx };
15241
+ } else {
15242
+ groupStyle = {
15243
+ gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,
15244
+ gap: itemGapPx
15245
+ };
15246
+ }
15247
+ const groupClasses = cn(
15248
+ layout === "grid" ? "grid" : "flex flex-col",
15249
+ groupClassName != null ? groupClassName : className
15250
+ );
15251
+ const baseOptionClass = cn(
15252
+ "relative flex items-start",
15253
+ "data-[disabled=true]:opacity-60 data-[disabled=true]:cursor-not-allowed",
15254
+ densityPaddingClass,
15255
+ optionClassName
15256
+ );
15257
+ const labelClassesBase = cn(
15258
+ "font-medium text-foreground",
15259
+ labelTextSizeClass,
15260
+ labelClassName
15261
+ );
15262
+ const descriptionClassesBase = cn(
15263
+ "mt-0.5 text-muted-foreground",
15264
+ descriptionTextSizeClass,
15265
+ descriptionClassName
15266
+ );
15267
+ return {
15268
+ groupStyle,
15269
+ groupClasses,
15270
+ baseOptionClass,
15271
+ labelClassesBase,
15272
+ descriptionClassesBase
15273
+ };
15274
+ }
15216
15275
  function RadioGroup({
15217
15276
  className,
15218
15277
  ...props
@@ -15250,6 +15309,139 @@ function RadioGroupItem({
15250
15309
  }
15251
15310
  );
15252
15311
  }
15312
+
15313
+ // src/lib/normalise-options.ts
15314
+ function isPrimitiveOption(raw) {
15315
+ return typeof raw === "string" || typeof raw === "number";
15316
+ }
15317
+ function asObject(raw) {
15318
+ return isPrimitiveOption(raw) ? { label: String(raw), value: raw } : raw;
15319
+ }
15320
+ var RENDER_KEYS = [
15321
+ "render",
15322
+ "renderOption",
15323
+ "renderItem",
15324
+ "renderLabel",
15325
+ "renderer"
15326
+ ];
15327
+ function resolveRender(obj) {
15328
+ if (!obj) return void 0;
15329
+ for (const k of RENDER_KEYS) {
15330
+ const maybe = obj[k];
15331
+ if (typeof maybe === "function") return maybe;
15332
+ }
15333
+ return void 0;
15334
+ }
15335
+ function resolveValue(raw, obj, index, optionValue) {
15336
+ var _a, _b, _c;
15337
+ return typeof optionValue === "function" ? optionValue(raw) : typeof optionValue === "string" ? obj[optionValue] : (_c = (_b = (_a = obj.value) != null ? _a : obj.id) != null ? _b : obj.key) != null ? _c : String(index);
15338
+ }
15339
+ function resolveLabelNode(raw, obj, value, optionLabel) {
15340
+ var _a, _b, _c;
15341
+ return typeof optionLabel === "function" ? optionLabel(raw) : typeof optionLabel === "string" ? (_b = (_a = obj[optionLabel]) != null ? _a : obj.label) != null ? _b : String(value) : (_c = obj.label) != null ? _c : String(value);
15342
+ }
15343
+ function resolveDescription(raw, obj, optionDescription) {
15344
+ return typeof optionDescription === "function" ? optionDescription(raw) : typeof optionDescription === "string" ? obj[optionDescription] : obj.description;
15345
+ }
15346
+ function resolveDisabled(raw, obj, optionDisabled) {
15347
+ return typeof optionDisabled === "function" ? optionDisabled(raw) : typeof optionDisabled === "string" ? !!obj[optionDisabled] : !!obj.disabled;
15348
+ }
15349
+ function resolveIcon(raw, obj, optionIcon) {
15350
+ return typeof optionIcon === "function" ? optionIcon(raw) : typeof optionIcon === "string" ? obj[optionIcon] : obj.icon;
15351
+ }
15352
+ function resolveKey(raw, obj, index, value, optionKey) {
15353
+ var _a, _b, _c, _d;
15354
+ return typeof optionKey === "function" ? optionKey(raw, index) : typeof optionKey === "string" ? (_b = (_a = obj[optionKey]) != null ? _a : value) != null ? _b : index : (_d = (_c = obj.key) != null ? _c : value) != null ? _d : index;
15355
+ }
15356
+ function resolveLabelText(labelNode, obj, value) {
15357
+ var _a;
15358
+ return typeof labelNode === "string" ? labelNode : typeof labelNode === "number" ? String(labelNode) : (_a = obj.labelText) != null ? _a : String(value);
15359
+ }
15360
+ function normalizeOne(raw, index, config) {
15361
+ const obj = asObject(raw);
15362
+ const value = resolveValue(raw, obj, index, config.optionValue);
15363
+ let labelNode = resolveLabelNode(raw, obj, value, config.optionLabel);
15364
+ if (config.autoCap && typeof labelNode === "string") {
15365
+ labelNode = capitalizeFirst(labelNode);
15366
+ }
15367
+ const labelText = resolveLabelText(labelNode, obj, value);
15368
+ const description = resolveDescription(raw, obj, config.optionDescription);
15369
+ const disabled = resolveDisabled(raw, obj, config.optionDisabled);
15370
+ const icon = resolveIcon(raw, obj, config.optionIcon);
15371
+ const key = resolveKey(raw, obj, index, value, config.optionKey);
15372
+ const render = resolveRender(obj);
15373
+ return {
15374
+ key: String(key),
15375
+ value,
15376
+ labelNode,
15377
+ labelText,
15378
+ description,
15379
+ disabled,
15380
+ icon,
15381
+ render,
15382
+ raw
15383
+ };
15384
+ }
15385
+ function globalNormalizeOptions(opts, config) {
15386
+ if (!opts || !opts.length) return [];
15387
+ return opts.map(
15388
+ (raw, index) => normalizeOne(raw, index, config)
15389
+ );
15390
+ }
15391
+ function globalNormalizeCheckBasedOptions(item, index, optionLabelKey, optionValueKey) {
15392
+ var _a, _b;
15393
+ const anyItem = item;
15394
+ const rawValue = optionValueKey != null ? anyItem[optionValueKey] : anyItem.value;
15395
+ const value = rawValue;
15396
+ const rawLabel = optionLabelKey != null ? anyItem[optionLabelKey] : (_a = anyItem.label) != null ? _a : String(rawValue != null ? rawValue : index);
15397
+ const description = anyItem.description;
15398
+ const disabled = !!anyItem.disabled;
15399
+ const key = (_b = anyItem.key) != null ? _b : index;
15400
+ const render = resolveRender(anyItem);
15401
+ return {
15402
+ key: String(key),
15403
+ value,
15404
+ label: rawLabel,
15405
+ description,
15406
+ disabled,
15407
+ render,
15408
+ raw: item
15409
+ };
15410
+ }
15411
+ function normalizeTree(opts, config, level = 0, parentValue, path = []) {
15412
+ if (!opts || !opts.length) return [];
15413
+ return opts.map((raw, index) => {
15414
+ const obj = asObject(raw);
15415
+ const base = normalizeOne(
15416
+ raw,
15417
+ index,
15418
+ config
15419
+ // (config shape matches; this avoids duplicating the resolver types)
15420
+ );
15421
+ const childrenRaw = obj.children;
15422
+ const nextPath = [...path, base.value];
15423
+ const children = normalizeTree(
15424
+ childrenRaw != null ? childrenRaw : [],
15425
+ config,
15426
+ level + 1,
15427
+ base.value,
15428
+ nextPath
15429
+ );
15430
+ return {
15431
+ ...base,
15432
+ level,
15433
+ parentValue,
15434
+ path,
15435
+ // ancestors only (EXACT behaviour preserved)
15436
+ hasChildren: !!children.length,
15437
+ children
15438
+ };
15439
+ });
15440
+ }
15441
+ function capitalizeFirst(label) {
15442
+ if (!label) return label;
15443
+ return label.charAt(0).toUpperCase() + label.slice(1);
15444
+ }
15253
15445
  function paddingForDensity(density) {
15254
15446
  switch (density) {
15255
15447
  case "compact":
@@ -15283,7 +15475,7 @@ function descriptionTextSize(size) {
15283
15475
  return "text-xs";
15284
15476
  }
15285
15477
  }
15286
- function capitalizeFirst(label) {
15478
+ function capitalizeFirst2(label) {
15287
15479
  if (!label) return label;
15288
15480
  return label.charAt(0).toUpperCase() + label.slice(1);
15289
15481
  }
@@ -15299,21 +15491,12 @@ function normalizeItems(items, mappers, optionValueKey, optionLabelKey) {
15299
15491
  }
15300
15492
  if (optionValueKey || optionLabelKey) {
15301
15493
  return items.map((item, index) => {
15302
- var _a, _b;
15303
- const anyItem = item;
15304
- const rawValue = optionValueKey != null ? anyItem[optionValueKey] : anyItem.value;
15305
- const value = rawValue;
15306
- const rawLabel = optionLabelKey != null ? anyItem[optionLabelKey] : (_a = anyItem.label) != null ? _a : String(rawValue != null ? rawValue : index);
15307
- const description = anyItem.description;
15308
- const disabled = !!anyItem.disabled;
15309
- const key = (_b = anyItem.key) != null ? _b : index;
15310
- return {
15311
- value,
15312
- label: rawLabel,
15313
- description,
15314
- disabled,
15315
- key
15316
- };
15494
+ return globalNormalizeCheckBasedOptions(
15495
+ item,
15496
+ index,
15497
+ optionLabelKey,
15498
+ optionValueKey
15499
+ );
15317
15500
  });
15318
15501
  }
15319
15502
  return items.map((item, index) => {
@@ -15400,54 +15583,31 @@ var InnerShadcnRadioVariant = (props, ref) => {
15400
15583
  );
15401
15584
  const handleRadioChange = React10.useCallback(
15402
15585
  (raw) => {
15403
- const found = normalized.find(
15404
- (item) => String(item.value) === raw
15405
- );
15586
+ const found = normalized.find((item) => String(item.value) === raw);
15406
15587
  if (!found) return;
15407
15588
  handleSelect(found.value);
15408
15589
  },
15409
15590
  [normalized, handleSelect]
15410
15591
  );
15411
- const groupStyle = React10.useMemo(() => {
15412
- if (!itemGapPx) {
15413
- if (layout === "grid") {
15414
- return {
15415
- gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`
15416
- };
15417
- }
15418
- return void 0;
15419
- }
15420
- if (layout === "list") {
15421
- return { rowGap: itemGapPx };
15422
- }
15423
- return {
15424
- gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,
15425
- gap: itemGapPx
15426
- };
15427
- }, [layout, columns, itemGapPx]);
15428
- const groupClasses = cn(
15429
- layout === "grid" ? "grid" : "flex flex-col",
15430
- groupClassName != null ? groupClassName : className
15431
- );
15432
- const baseOptionClass = cn(
15433
- // layout container for each option row
15434
- "relative flex items-start",
15435
- // keep disabled styles
15436
- "data-[disabled=true]:opacity-60 data-[disabled=true]:cursor-not-allowed",
15437
- // vertical padding from density
15438
- paddingForDensity(density),
15439
- optionClassName
15440
- );
15441
- const labelClassesBase = cn(
15442
- "font-medium text-foreground",
15443
- labelTextSize(size),
15444
- labelClassName
15445
- );
15446
- const descriptionClassesBase = cn(
15447
- "mt-0.5 text-muted-foreground",
15448
- descriptionTextSize(size),
15449
- descriptionClassName
15450
- );
15592
+ const {
15593
+ groupStyle,
15594
+ groupClasses,
15595
+ baseOptionClass,
15596
+ labelClassesBase,
15597
+ descriptionClassesBase
15598
+ } = buildGroupLayoutClasses({
15599
+ layout,
15600
+ columns,
15601
+ itemGapPx,
15602
+ groupClassName,
15603
+ className,
15604
+ optionClassName,
15605
+ labelClassName,
15606
+ descriptionClassName,
15607
+ densityPaddingClass: paddingForDensity(density),
15608
+ labelTextSizeClass: labelTextSize(size),
15609
+ descriptionTextSizeClass: descriptionTextSize(size)
15610
+ });
15451
15611
  return /* @__PURE__ */ jsx(
15452
15612
  RadioGroup,
15453
15613
  {
@@ -15467,7 +15627,7 @@ var InnerShadcnRadioVariant = (props, ref) => {
15467
15627
  "data-slot": "radio-group",
15468
15628
  ...restGroupProps,
15469
15629
  children: normalized.map((item, index) => {
15470
- var _a;
15630
+ var _a, _b;
15471
15631
  const itemString = String(item.value);
15472
15632
  const selected = selectedString === itemString;
15473
15633
  const optionDisabled = !!disabled || !!item.disabled;
@@ -15477,7 +15637,7 @@ var InnerShadcnRadioVariant = (props, ref) => {
15477
15637
  if (autoCap && typeof item.label === "string") {
15478
15638
  displayItem = {
15479
15639
  ...item,
15480
- label: capitalizeFirst(item.label)
15640
+ label: capitalizeFirst2(item.label)
15481
15641
  };
15482
15642
  }
15483
15643
  const radioNode = /* @__PURE__ */ jsx(
@@ -15489,7 +15649,8 @@ var InnerShadcnRadioVariant = (props, ref) => {
15489
15649
  className: "mt-1"
15490
15650
  }
15491
15651
  );
15492
- if (renderOption) {
15652
+ const renderer = (_b = item.render) != null ? _b : renderOption;
15653
+ if (renderer) {
15493
15654
  return /* @__PURE__ */ jsx(
15494
15655
  "div",
15495
15656
  {
@@ -15497,7 +15658,7 @@ var InnerShadcnRadioVariant = (props, ref) => {
15497
15658
  "data-checked": selected ? "true" : "false",
15498
15659
  "data-disabled": optionDisabled ? "true" : "false",
15499
15660
  className: baseOptionClass,
15500
- children: renderOption({
15661
+ children: renderer({
15501
15662
  item: displayItem,
15502
15663
  index,
15503
15664
  selected,
@@ -15543,7 +15704,9 @@ var InnerShadcnRadioVariant = (props, ref) => {
15543
15704
  }
15544
15705
  );
15545
15706
  };
15546
- var ShadcnRadioVariant = React10.forwardRef(InnerShadcnRadioVariant);
15707
+ var ShadcnRadioVariant = React10.forwardRef(
15708
+ InnerShadcnRadioVariant
15709
+ );
15547
15710
 
15548
15711
  // src/variants/core/radio.tsx
15549
15712
  var radioVariantModule = {
@@ -15655,7 +15818,7 @@ function descriptionTextSize2(size) {
15655
15818
  return "text-xs";
15656
15819
  }
15657
15820
  }
15658
- function capitalizeFirst2(label) {
15821
+ function capitalizeFirst3(label) {
15659
15822
  if (!label) return label;
15660
15823
  return label.charAt(0).toUpperCase() + label.slice(1);
15661
15824
  }
@@ -15673,21 +15836,16 @@ function normalizeItems2(items, mappers, optionValueKey, optionLabelKey) {
15673
15836
  }
15674
15837
  if (optionValueKey || optionLabelKey) {
15675
15838
  return items.map((item, index) => {
15676
- var _a, _b;
15677
15839
  const anyItem = item;
15678
- const rawValue = optionValueKey != null ? anyItem[optionValueKey] : anyItem.value;
15679
- const value = rawValue;
15680
- const rawLabel = optionLabelKey != null ? anyItem[optionLabelKey] : (_a = anyItem.label) != null ? _a : String(rawValue != null ? rawValue : index);
15681
- const description = anyItem.description;
15682
- const disabled = !!anyItem.disabled;
15683
- const key = (_b = anyItem.key) != null ? _b : index;
15840
+ const normalised = globalNormalizeCheckBasedOptions(
15841
+ item,
15842
+ index,
15843
+ optionLabelKey,
15844
+ optionValueKey
15845
+ );
15684
15846
  const tristate = anyItem.tristate;
15685
15847
  return {
15686
- value,
15687
- label: rawLabel,
15688
- description,
15689
- disabled,
15690
- key,
15848
+ ...normalised,
15691
15849
  tristate
15692
15850
  };
15693
15851
  });
@@ -15782,7 +15940,7 @@ var InnerShadcnCheckboxVariant = (props, ref) => {
15782
15940
  };
15783
15941
  let labelText = singleLabel != null ? singleLabel : void 0;
15784
15942
  if (autoCap && typeof labelText === "string") {
15785
- labelText = capitalizeFirst2(labelText);
15943
+ labelText = capitalizeFirst3(labelText);
15786
15944
  }
15787
15945
  const descriptionText = singleDescription != null ? singleDescription : void 0;
15788
15946
  const labelCls = cn(
@@ -15842,43 +16000,25 @@ var InnerShadcnCheckboxVariant = (props, ref) => {
15842
16000
  ),
15843
16001
  [items, mappers, optionValue, optionLabel]
15844
16002
  );
15845
- const groupStyle = React10.useMemo(() => {
15846
- if (!itemGapPx) {
15847
- if (layout === "grid") {
15848
- return {
15849
- gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`
15850
- };
15851
- }
15852
- return void 0;
15853
- }
15854
- if (layout === "list") {
15855
- return { rowGap: itemGapPx };
15856
- }
15857
- return {
15858
- gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,
15859
- gap: itemGapPx
15860
- };
15861
- }, [layout, columns, itemGapPx]);
15862
- const groupClasses = cn(
15863
- layout === "grid" ? "grid" : "flex flex-col",
15864
- groupClassName != null ? groupClassName : className
15865
- );
15866
- const baseOptionClass = cn(
15867
- "relative flex items-start",
15868
- "data-[disabled=true]:opacity-60 data-[disabled=true]:cursor-not-allowed",
15869
- paddingForDensity2(density),
15870
- optionClassName
15871
- );
15872
- const labelClassesBase = cn(
15873
- "font-medium text-foreground",
15874
- labelTextSize2(size),
15875
- labelClassName
15876
- );
15877
- const descriptionClassesBase = cn(
15878
- "mt-0.5 text-muted-foreground",
15879
- descriptionTextSize2(size),
15880
- descriptionClassName
15881
- );
16003
+ const {
16004
+ groupStyle,
16005
+ groupClasses,
16006
+ baseOptionClass,
16007
+ labelClassesBase,
16008
+ descriptionClassesBase
16009
+ } = buildGroupLayoutClasses({
16010
+ layout,
16011
+ columns,
16012
+ itemGapPx,
16013
+ groupClassName,
16014
+ className,
16015
+ optionClassName,
16016
+ labelClassName,
16017
+ descriptionClassName,
16018
+ densityPaddingClass: paddingForDensity2(density),
16019
+ labelTextSizeClass: labelTextSize2(size),
16020
+ descriptionTextSizeClass: descriptionTextSize2(size)
16021
+ });
15882
16022
  const findEntryIndex = React10.useCallback(
15883
16023
  (val) => {
15884
16024
  if (!groupValue) return -1;
@@ -15974,7 +16114,7 @@ var InnerShadcnCheckboxVariant = (props, ref) => {
15974
16114
  style: groupStyle,
15975
16115
  ...restProps,
15976
16116
  children: normalized.map((item, index) => {
15977
- var _a, _b, _c;
16117
+ var _a, _b, _c, _d;
15978
16118
  const effectiveTristate = (_b = (_a = item.tristate) != null ? _a : tristateDefault) != null ? _b : false;
15979
16119
  const currentState = getEntryState(item.value);
15980
16120
  const internalState = effectiveTristate ? currentState : currentState === "none" ? false : currentState;
@@ -15985,7 +16125,7 @@ var InnerShadcnCheckboxVariant = (props, ref) => {
15985
16125
  if (autoCap && typeof item.label === "string") {
15986
16126
  displayItem = {
15987
16127
  ...item,
15988
- label: capitalizeFirst2(item.label)
16128
+ label: capitalizeFirst3(item.label)
15989
16129
  };
15990
16130
  }
15991
16131
  const checkboxNode = /* @__PURE__ */ jsx(
@@ -16012,7 +16152,8 @@ var InnerShadcnCheckboxVariant = (props, ref) => {
16012
16152
  disabled: getEntryState(item.value) === "none"
16013
16153
  }
16014
16154
  ) : null;
16015
- if (renderOption) {
16155
+ const renderer = (_d = item.render) != null ? _d : renderOption;
16156
+ if (renderer) {
16016
16157
  return /* @__PURE__ */ jsxs(
16017
16158
  "div",
16018
16159
  {
@@ -16020,7 +16161,7 @@ var InnerShadcnCheckboxVariant = (props, ref) => {
16020
16161
  "data-disabled": optionDisabled ? "true" : "false",
16021
16162
  className: baseOptionClass,
16022
16163
  children: [
16023
- renderOption({
16164
+ renderer({
16024
16165
  item: displayItem,
16025
16166
  index,
16026
16167
  state: internalState,
@@ -16032,7 +16173,11 @@ var InnerShadcnCheckboxVariant = (props, ref) => {
16032
16173
  click() {
16033
16174
  if (optionDisabled) return;
16034
16175
  const nextInternal = effectiveTristate ? internalState === "none" ? true : internalState === true ? false : "none" : internalState === true ? false : true;
16035
- updateGroupValue(item.value, nextInternal, effectiveTristate);
16176
+ updateGroupValue(
16177
+ item.value,
16178
+ nextInternal,
16179
+ effectiveTristate
16180
+ );
16036
16181
  },
16037
16182
  checkbox: checkboxNode
16038
16183
  }),
@@ -16057,14 +16202,17 @@ var InnerShadcnCheckboxVariant = (props, ref) => {
16057
16202
  children: [
16058
16203
  checkboxNode,
16059
16204
  /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col", children: [
16060
- /* @__PURE__ */ jsx("span", { className: cn(labelClassesBase, optionLabelClassName), children: displayItem.label }),
16061
- displayItem.description != null && /* @__PURE__ */ jsx(
16205
+ /* @__PURE__ */ jsx(
16062
16206
  "span",
16063
16207
  {
16064
- className: descriptionClassesBase,
16065
- children: displayItem.description
16208
+ className: cn(
16209
+ labelClassesBase,
16210
+ optionLabelClassName
16211
+ ),
16212
+ children: displayItem.label
16066
16213
  }
16067
- )
16214
+ ),
16215
+ displayItem.description != null && /* @__PURE__ */ jsx("span", { className: descriptionClassesBase, children: displayItem.description })
16068
16216
  ] })
16069
16217
  ]
16070
16218
  }
@@ -16078,7 +16226,9 @@ var InnerShadcnCheckboxVariant = (props, ref) => {
16078
16226
  }
16079
16227
  );
16080
16228
  };
16081
- var ShadcnCheckboxVariant = React10.forwardRef(InnerShadcnCheckboxVariant);
16229
+ var ShadcnCheckboxVariant = React10.forwardRef(
16230
+ InnerShadcnCheckboxVariant
16231
+ );
16082
16232
 
16083
16233
  // src/variants/core/checkbox.tsx
16084
16234
  var checkboxModule = {
@@ -16099,39 +16249,6 @@ var checkboxModule = {
16099
16249
  tags: ["checkbox", "group", "boolean", "tri-state"]
16100
16250
  }
16101
16251
  };
16102
-
16103
- // src/lib/normalise-selects.ts
16104
- function globalNormalizeOptions(opts, config) {
16105
- if (!opts || !opts.length) return [];
16106
- return opts.map((raw, index) => {
16107
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
16108
- const asObj = typeof raw === "string" || typeof raw === "number" ? { label: String(raw), value: raw } : raw;
16109
- const value = typeof config.optionValue === "function" ? config.optionValue(raw) : typeof config.optionValue === "string" ? asObj[config.optionValue] : (_c = (_b = (_a = asObj.value) != null ? _a : asObj.id) != null ? _b : asObj.key) != null ? _c : String(index);
16110
- let labelNode = typeof config.optionLabel === "function" ? config.optionLabel(raw) : typeof config.optionLabel === "string" ? (_e = (_d = asObj[config.optionLabel]) != null ? _d : asObj.label) != null ? _e : String(value) : (_f = asObj.label) != null ? _f : String(value);
16111
- if (config.autoCap && typeof labelNode === "string") {
16112
- labelNode = capitalizeFirst3(labelNode);
16113
- }
16114
- const labelText = typeof labelNode === "string" ? labelNode : typeof labelNode === "number" ? String(labelNode) : (_g = asObj.labelText) != null ? _g : String(value);
16115
- const description = typeof config.optionDescription === "function" ? config.optionDescription(raw) : typeof config.optionDescription === "string" ? asObj[config.optionDescription] : asObj.description;
16116
- const disabled = typeof config.optionDisabled === "function" ? config.optionDisabled(raw) : typeof config.optionDisabled === "string" ? !!asObj[config.optionDisabled] : !!asObj.disabled;
16117
- const icon = typeof config.optionIcon === "function" ? config.optionIcon(raw) : typeof config.optionIcon === "string" ? asObj[config.optionIcon] : asObj.icon;
16118
- const key = typeof config.optionKey === "function" ? config.optionKey(raw, index) : typeof config.optionKey === "string" ? (_i = (_h = asObj[config.optionKey]) != null ? _h : value) != null ? _i : index : (_k = (_j = asObj.key) != null ? _j : value) != null ? _k : index;
16119
- return {
16120
- key: String(key),
16121
- value,
16122
- labelNode,
16123
- labelText,
16124
- description,
16125
- disabled,
16126
- icon,
16127
- raw
16128
- };
16129
- });
16130
- }
16131
- function capitalizeFirst3(label) {
16132
- if (!label) return label;
16133
- return label.charAt(0).toUpperCase() + label.slice(1);
16134
- }
16135
16252
  function normalizeOptions(opts, config) {
16136
16253
  return globalNormalizeOptions(opts, config);
16137
16254
  }
@@ -16185,6 +16302,8 @@ var ShadcnSelectVariant = React10.forwardRef(function ShadcnSelectVariant2(props
16185
16302
  contentClassName,
16186
16303
  renderOption,
16187
16304
  renderValue,
16305
+ // Mode
16306
+ mode = "default",
16188
16307
  // Icons & controls
16189
16308
  leadingIcons,
16190
16309
  trailingIcons,
@@ -16198,11 +16317,15 @@ var ShadcnSelectVariant = React10.forwardRef(function ShadcnSelectVariant2(props
16198
16317
  trailingControlClassName,
16199
16318
  joinControls = true,
16200
16319
  extendBoxToControls = true,
16320
+ // Button mode only
16321
+ button,
16322
+ children,
16201
16323
  // Virtual scroll / incremental render
16202
16324
  virtualScroll = false,
16203
16325
  virtualScrollPageSize = 50,
16204
16326
  virtualScrollThreshold = 48
16205
16327
  } = props;
16328
+ const isButtonMode = mode === "button";
16206
16329
  const [open, setOpen] = React10.useState(false);
16207
16330
  const [query, setQuery] = React10.useState("");
16208
16331
  const items = React10.useMemo(
@@ -16295,18 +16418,19 @@ var ShadcnSelectVariant = React10.forwardRef(function ShadcnSelectVariant2(props
16295
16418
  const padCls = triggerPadding(density);
16296
16419
  const showClear = clearable && value != null;
16297
16420
  const resolvedLeadingIcons = (() => {
16421
+ if (isButtonMode) return [];
16298
16422
  if (leadingIcons && leadingIcons.length) return leadingIcons;
16299
16423
  if (icon) return [icon];
16300
16424
  return [];
16301
16425
  })();
16302
- const resolvedTrailingIcons = trailingIcons != null ? trailingIcons : [];
16426
+ const resolvedTrailingIcons = isButtonMode ? [] : trailingIcons != null ? trailingIcons : [];
16303
16427
  const baseIconGap = iconGap != null ? iconGap : 4;
16304
16428
  const leadingGap = leadingIconSpacing != null ? leadingIconSpacing : baseIconGap;
16305
16429
  const trailingGap = trailingIconSpacing != null ? trailingIconSpacing : baseIconGap;
16306
16430
  const hasLeadingIcons = resolvedLeadingIcons.length > 0;
16307
16431
  const hasTrailingIcons = resolvedTrailingIcons.length > 0;
16308
- const hasLeadingControl = !!leadingControl;
16309
- const hasTrailingControl = !!trailingControl;
16432
+ const hasLeadingControl = !isButtonMode && !!leadingControl;
16433
+ const hasTrailingControl = !isButtonMode && !!trailingControl;
16310
16434
  const hasControls = hasLeadingControl || hasTrailingControl;
16311
16435
  const triggerInner = renderValue ? renderValue({
16312
16436
  selectedItem,
@@ -16321,7 +16445,57 @@ var ShadcnSelectVariant = React10.forwardRef(function ShadcnSelectVariant2(props
16321
16445
  "focus-within:border-ring focus-within:ring-ring/50 focus-within:ring-[3px]",
16322
16446
  "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive"
16323
16447
  );
16324
- const TriggerBody = /* @__PURE__ */ jsx(
16448
+ const ButtonModeTrigger = React10.useMemo(() => {
16449
+ if (!isButtonMode) return null;
16450
+ const selectedValue = value;
16451
+ const renderable = button != null ? button : children;
16452
+ const content = (() => {
16453
+ var _a2, _b2, _c, _d;
16454
+ if (typeof renderable === "function") {
16455
+ return renderable({
16456
+ open,
16457
+ selectedItem,
16458
+ selectedValue,
16459
+ placeholder
16460
+ });
16461
+ }
16462
+ if (renderable != null) return renderable;
16463
+ const iconNode = (_c = (_b2 = selectedItem == null ? void 0 : selectedItem.icon) != null ? _b2 : (_a2 = items.find((it) => it.icon)) == null ? void 0 : _a2.icon) != null ? _c : null;
16464
+ if (iconNode) {
16465
+ return /* @__PURE__ */ jsx("span", { className: "inline-flex items-center justify-center", children: iconNode });
16466
+ }
16467
+ return /* @__PURE__ */ jsx("span", { className: "truncate", children: (_d = selectedItem == null ? void 0 : selectedItem.labelNode) != null ? _d : placeholder != null ? placeholder : "Select..." });
16468
+ })();
16469
+ return /* @__PURE__ */ jsx(
16470
+ "button",
16471
+ {
16472
+ ref: _ref,
16473
+ type: "button",
16474
+ disabled: disabled || readOnly,
16475
+ className: cn(
16476
+ "inline-flex items-center justify-center",
16477
+ "focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50",
16478
+ triggerClassName
16479
+ ),
16480
+ "aria-label": (selectedItem == null ? void 0 : selectedItem.labelText) ? `Selected: ${selectedItem.labelText}` : "Select",
16481
+ children: content
16482
+ }
16483
+ );
16484
+ }, [
16485
+ isButtonMode,
16486
+ button,
16487
+ children,
16488
+ open,
16489
+ selectedItem,
16490
+ value,
16491
+ placeholder,
16492
+ items,
16493
+ disabled,
16494
+ readOnly,
16495
+ triggerClassName,
16496
+ _ref
16497
+ ]);
16498
+ const TriggerBody = isButtonMode ? /* @__PURE__ */ jsx(SelectTrigger, { asChild: true, children: ButtonModeTrigger }) : /* @__PURE__ */ jsx(
16325
16499
  SelectTrigger,
16326
16500
  {
16327
16501
  onPointerDown: (e) => {
@@ -16414,7 +16588,7 @@ var ShadcnSelectVariant = React10.forwardRef(function ShadcnSelectVariant2(props
16414
16588
  /* @__PURE__ */ jsxs(
16415
16589
  SelectContent,
16416
16590
  {
16417
- className: cn("min-w-[8rem]", contentClassName),
16591
+ className: cn("min-w-32", contentClassName),
16418
16592
  children: [
16419
16593
  searchable && /* @__PURE__ */ jsx("div", { className: "p-1", children: /* @__PURE__ */ jsx(
16420
16594
  Input,
@@ -16440,6 +16614,7 @@ var ShadcnSelectVariant = React10.forwardRef(function ShadcnSelectVariant2(props
16440
16614
  onScroll: handleListScroll,
16441
16615
  children: [
16442
16616
  renderedItems.map((item, index) => {
16617
+ var _a2;
16443
16618
  const optionNode = /* @__PURE__ */ jsx(
16444
16619
  SelectItem,
16445
16620
  {
@@ -16455,8 +16630,9 @@ var ShadcnSelectVariant = React10.forwardRef(function ShadcnSelectVariant2(props
16455
16630
  },
16456
16631
  item.key
16457
16632
  );
16458
- if (!renderOption) return optionNode;
16459
- return renderOption({
16633
+ const renderer = (_a2 = item.render) != null ? _a2 : renderOption;
16634
+ if (!renderer) return optionNode;
16635
+ return renderer({
16460
16636
  item,
16461
16637
  selected: selectedItem != null && String(selectedItem.value) === String(item.value),
16462
16638
  index,
@@ -16481,7 +16657,7 @@ var ShadcnSelectVariant = React10.forwardRef(function ShadcnSelectVariant2(props
16481
16657
  ]
16482
16658
  }
16483
16659
  );
16484
- if (!hasControls) {
16660
+ if (isButtonMode || !hasControls) {
16485
16661
  return /* @__PURE__ */ jsx(
16486
16662
  "div",
16487
16663
  {
@@ -17252,6 +17428,7 @@ var ShadcnMultiSelectVariant = React10.forwardRef(function ShadcnMultiSelectVari
17252
17428
  }
17253
17429
  ),
17254
17430
  filteredItems.length === 0 ? /* @__PURE__ */ jsx("div", { className: "px-2 py-1.5 text-xs text-muted-foreground", children: emptySearchText != null ? emptySearchText : "No results found" }) : filteredItems.map((item, index) => {
17431
+ var _a2;
17255
17432
  const selected = selectedValues.has(item.value);
17256
17433
  const row = /* @__PURE__ */ jsxs(
17257
17434
  "button",
@@ -17284,8 +17461,9 @@ var ShadcnMultiSelectVariant = React10.forwardRef(function ShadcnMultiSelectVari
17284
17461
  },
17285
17462
  item.key
17286
17463
  );
17287
- if (!renderOption) return row;
17288
- return renderOption({
17464
+ const renderer = (_a2 = item.render) != null ? _a2 : renderOption;
17465
+ if (!renderer) return row;
17466
+ return renderer({
17289
17467
  item,
17290
17468
  selected,
17291
17469
  index,
@@ -18504,52 +18682,6 @@ var customVariant = {
18504
18682
  Variant: ShadcnCustomVariant
18505
18683
  };
18506
18684
  var custom_default = customVariant;
18507
- function capitalizeFirst4(label) {
18508
- if (!label) return label;
18509
- return label.charAt(0).toUpperCase() + label.slice(1);
18510
- }
18511
- function normalizeTree(opts, config, level = 0, parentValue, path = []) {
18512
- if (!opts || !opts.length) return [];
18513
- return opts.map((raw, index) => {
18514
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
18515
- const asObj = typeof raw === "string" || typeof raw === "number" ? { label: String(raw), value: raw } : raw;
18516
- const value = typeof config.optionValue === "function" ? config.optionValue(raw) : typeof config.optionValue === "string" ? asObj[config.optionValue] : (_c = (_b = (_a = asObj.value) != null ? _a : asObj.id) != null ? _b : asObj.key) != null ? _c : String(index);
18517
- let labelNode = typeof config.optionLabel === "function" ? config.optionLabel(raw) : typeof config.optionLabel === "string" ? (_e = (_d = asObj[config.optionLabel]) != null ? _d : asObj.label) != null ? _e : String(value) : (_f = asObj.label) != null ? _f : String(value);
18518
- if (config.autoCap && typeof labelNode === "string") {
18519
- labelNode = capitalizeFirst4(labelNode);
18520
- }
18521
- const labelText = typeof labelNode === "string" ? labelNode : typeof labelNode === "number" ? String(labelNode) : (_g = asObj.labelText) != null ? _g : String(value);
18522
- const description = typeof config.optionDescription === "function" ? config.optionDescription(raw) : typeof config.optionDescription === "string" ? asObj[config.optionDescription] : asObj.description;
18523
- const disabled = typeof config.optionDisabled === "function" ? config.optionDisabled(raw) : typeof config.optionDisabled === "string" ? !!asObj[config.optionDisabled] : !!asObj.disabled;
18524
- const icon = typeof config.optionIcon === "function" ? config.optionIcon(raw) : typeof config.optionIcon === "string" ? asObj[config.optionIcon] : asObj.icon;
18525
- const key = typeof config.optionKey === "function" ? config.optionKey(raw, index) : typeof config.optionKey === "string" ? (_i = (_h = asObj[config.optionKey]) != null ? _h : value) != null ? _i : index : (_k = (_j = asObj.key) != null ? _j : value) != null ? _k : index;
18526
- const childrenRaw = asObj.children;
18527
- const nextPath = [...path, value];
18528
- const children = normalizeTree(
18529
- childrenRaw != null ? childrenRaw : [],
18530
- config,
18531
- level + 1,
18532
- value,
18533
- nextPath
18534
- );
18535
- return {
18536
- key: String(key),
18537
- value,
18538
- labelNode,
18539
- labelText,
18540
- description,
18541
- disabled,
18542
- icon,
18543
- level,
18544
- parentValue,
18545
- path,
18546
- // ancestors only
18547
- hasChildren: !!children.length,
18548
- children,
18549
- raw
18550
- };
18551
- });
18552
- }
18553
18685
  function flattenTree(nodes) {
18554
18686
  const result = [];
18555
18687
  function recurse(list) {
@@ -18954,6 +19086,7 @@ var ShadcnTreeSelectVariant = React10.forwardRef(function ShadcnTreeSelectVarian
18954
19086
  emptyLabel && tree.length === 0 && !query && /* @__PURE__ */ jsx("div", { className: "px-4 py-3 text-sm text-center text-muted-foreground", children: emptyLabel }),
18955
19087
  tree.length > 0 && displayedNodes.length === 0 && /* @__PURE__ */ jsx("div", { className: "px-4 py-3 text-sm text-center text-muted-foreground", children: emptySearchText != null ? emptySearchText : "No results found" }),
18956
19088
  displayedNodes.map((item, index) => {
19089
+ var _a;
18957
19090
  const selected = selectedValues.includes(item.value);
18958
19091
  const isExpanded = expanded.has(item.value);
18959
19092
  const parentInLeafOnly = leafOnly && item.hasChildren;
@@ -19017,10 +19150,11 @@ var ShadcnTreeSelectVariant = React10.forwardRef(function ShadcnTreeSelectVarian
19017
19150
  ]
19018
19151
  }
19019
19152
  );
19020
- if (!renderOption) {
19153
+ const renderer = (_a = item.render) != null ? _a : renderOption;
19154
+ if (!renderer) {
19021
19155
  return /* @__PURE__ */ jsx(React10.Fragment, { children: optionNode }, item.key);
19022
19156
  }
19023
- const rendered = renderOption({
19157
+ const rendered = renderer({
19024
19158
  item,
19025
19159
  selected,
19026
19160
  index,
@@ -20378,7 +20512,7 @@ function normalizeValue(val, multiple) {
20378
20512
  if (Array.isArray(val)) return val[0] || "";
20379
20513
  return val || "";
20380
20514
  }
20381
- function capitalizeFirst5(label) {
20515
+ function capitalizeFirst4(label) {
20382
20516
  if (!label) return label;
20383
20517
  return label.charAt(0).toUpperCase() + label.slice(1);
20384
20518
  }
@@ -20404,7 +20538,7 @@ function normalizeOption(input, {
20404
20538
  label2 = String(rawValue != null ? rawValue : value2);
20405
20539
  }
20406
20540
  if (autoCap && typeof label2 === "string") {
20407
- label2 = capitalizeFirst5(label2);
20541
+ label2 = capitalizeFirst4(label2);
20408
20542
  }
20409
20543
  const icon = optionIcon != null ? anyInput[optionIcon] : (_b = anyInput.icon) != null ? _b : void 0;
20410
20544
  const disabled = optionDisabled != null ? !!anyInput[optionDisabled] : !!anyInput.disabled;
@@ -20426,7 +20560,7 @@ function normalizeOption(input, {
20426
20560
  const value2 = String(input);
20427
20561
  let label2 = value2;
20428
20562
  if (autoCap && typeof label2 === "string") {
20429
- label2 = capitalizeFirst5(label2);
20563
+ label2 = capitalizeFirst4(label2);
20430
20564
  }
20431
20565
  return {
20432
20566
  ui: {
@@ -20440,7 +20574,7 @@ function normalizeOption(input, {
20440
20574
  const value = String(baseValue);
20441
20575
  let label = anyInput.label != null ? anyInput.label : String(value);
20442
20576
  if (autoCap && typeof label === "string") {
20443
- label = capitalizeFirst5(label);
20577
+ label = capitalizeFirst4(label);
20444
20578
  }
20445
20579
  return {
20446
20580
  ui: {