@lobb-js/studio 0.14.0 → 0.15.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.
@@ -8,26 +8,47 @@
8
8
 
9
9
  const { value, enum: enumOptions }: Props = $props();
10
10
 
11
- const levelClasses: Record<string, string> = {
12
- success: "bg-green-100 text-green-700 border-green-200",
13
- warning: "bg-yellow-100 text-yellow-700 border-yellow-300",
14
- danger: "bg-red-100 text-red-700 border-red-200",
15
- info: "bg-blue-100 text-blue-700 border-blue-200",
16
- neutral: "bg-gray-100 text-gray-600 border-gray-200",
17
- muted: "bg-gray-50 text-gray-400 border-gray-100",
11
+ const colorClasses: Record<string, string> = {
12
+ red: "bg-red-100 text-red-700 border-red-200 dark:bg-red-900/30 dark:text-red-300 dark:border-red-800",
13
+ rose: "bg-rose-100 text-rose-700 border-rose-200 dark:bg-rose-900/30 dark:text-rose-300 dark:border-rose-800",
14
+ pink: "bg-pink-100 text-pink-700 border-pink-200 dark:bg-pink-900/30 dark:text-pink-300 dark:border-pink-800",
15
+ fuchsia: "bg-fuchsia-100 text-fuchsia-700 border-fuchsia-200 dark:bg-fuchsia-900/30 dark:text-fuchsia-300 dark:border-fuchsia-800",
16
+ purple: "bg-purple-100 text-purple-700 border-purple-200 dark:bg-purple-900/30 dark:text-purple-300 dark:border-purple-800",
17
+ violet: "bg-violet-100 text-violet-700 border-violet-200 dark:bg-violet-900/30 dark:text-violet-300 dark:border-violet-800",
18
+ indigo: "bg-indigo-100 text-indigo-700 border-indigo-200 dark:bg-indigo-900/30 dark:text-indigo-300 dark:border-indigo-800",
19
+ blue: "bg-blue-100 text-blue-700 border-blue-200 dark:bg-blue-900/30 dark:text-blue-300 dark:border-blue-800",
20
+ sky: "bg-sky-100 text-sky-700 border-sky-200 dark:bg-sky-900/30 dark:text-sky-300 dark:border-sky-800",
21
+ cyan: "bg-cyan-100 text-cyan-700 border-cyan-200 dark:bg-cyan-900/30 dark:text-cyan-300 dark:border-cyan-800",
22
+ teal: "bg-teal-100 text-teal-700 border-teal-200 dark:bg-teal-900/30 dark:text-teal-300 dark:border-teal-800",
23
+ emerald: "bg-emerald-100 text-emerald-700 border-emerald-200 dark:bg-emerald-900/30 dark:text-emerald-300 dark:border-emerald-800",
24
+ green: "bg-green-100 text-green-700 border-green-200 dark:bg-green-900/30 dark:text-green-300 dark:border-green-800",
25
+ lime: "bg-lime-100 text-lime-700 border-lime-200 dark:bg-lime-900/30 dark:text-lime-300 dark:border-lime-800",
26
+ yellow: "bg-yellow-100 text-yellow-700 border-yellow-300 dark:bg-yellow-900/30 dark:text-yellow-300 dark:border-yellow-800",
27
+ amber: "bg-amber-100 text-amber-700 border-amber-200 dark:bg-amber-900/30 dark:text-amber-300 dark:border-amber-800",
28
+ orange: "bg-orange-100 text-orange-700 border-orange-200 dark:bg-orange-900/30 dark:text-orange-300 dark:border-orange-800",
29
+ slate: "bg-slate-100 text-slate-600 border-slate-200 dark:bg-slate-800/50 dark:text-slate-300 dark:border-slate-700",
30
+ zinc: "bg-zinc-100 text-zinc-600 border-zinc-200 dark:bg-zinc-800/50 dark:text-zinc-300 dark:border-zinc-700",
31
+ gray: "bg-gray-100 text-gray-600 border-gray-200 dark:bg-gray-800/50 dark:text-gray-300 dark:border-gray-700",
32
+ stone: "bg-stone-100 text-stone-600 border-stone-200 dark:bg-stone-800/50 dark:text-stone-300 dark:border-stone-700",
33
+ neutral: "bg-neutral-100 text-neutral-600 border-neutral-200 dark:bg-neutral-800/50 dark:text-neutral-300 dark:border-neutral-700",
18
34
  };
19
35
 
20
36
  const normalizedOptions = $derived(
21
- (enumOptions as Array<string | EnumOption>).map((e) =>
22
- typeof e === "string" ? { value: e, level: "neutral" as const } : e,
37
+ (enumOptions as Array<string | number | EnumOption>).map((e) =>
38
+ typeof e === "object" ? e : { value: e, color: undefined, description: undefined },
23
39
  ),
24
40
  );
25
41
 
26
- const enumOption = $derived(normalizedOptions.find((e) => e.value === value));
42
+ const enumOption = $derived(normalizedOptions.find((e) => String(e.value) === String(value)));
27
43
  </script>
28
44
 
29
45
  {#if enumOption}
30
- <span class="px-2 py-0.5 rounded-full text-xs font-medium border {levelClasses[enumOption.level]}">
31
- {value}
46
+ <span class="flex items-center gap-1.5">
47
+ <span class="px-2 py-0.5 rounded-full text-xs font-medium border {enumOption.color ? colorClasses[enumOption.color] : colorClasses['gray']}">
48
+ {enumOption.value}
49
+ </span>
50
+ {#if enumOption.description}
51
+ <span class="text-xs text-muted-foreground">{enumOption.description}</span>
52
+ {/if}
32
53
  </span>
33
54
  {/if}
@@ -93,75 +93,60 @@
93
93
  {destructive}
94
94
  />
95
95
  </ExtensionsComponents>
96
- {:else if field.type === "string" && field.enum}
97
- {@const rawEnum = field.enum as (string | EnumOption)[]}
98
- {@const enumOptions = rawEnum.map((e): EnumOption => typeof e === "string" ? { value: e, level: "neutral" } : e)}
96
+ {:else if field.enum}
97
+ {@const rawEnum = field.enum as (string | number | EnumOption)[]}
98
+ {@const isEnumOption = rawEnum.length > 0 && typeof rawEnum[0] === "object"}
99
+ {@const enumOptions = isEnumOption ? rawEnum as EnumOption[] : undefined}
99
100
  <Select.Root
100
101
  type="single"
101
- onValueChange={(newValue) => {
102
- value = newValue;
103
- }}
102
+ bind:value={
103
+ () => value != null ? String(value) : null,
104
+ (v) => {
105
+ if (v == null) { value = null; return; }
106
+ const isNumeric = field.type === "integer" || field.type === "long" || field.type === "decimal" || field.type === "float";
107
+ value = isNumeric ? Number(v) : v;
108
+ }
109
+ }
104
110
  >
105
111
  <Select.Trigger
106
- placeholder={ui?.placeholder ? ui.placeholder : "NULL"}
107
112
  class="
108
113
  h-9 w-full bg-muted/30 pr-8
109
114
  {destructive ? 'border-destructive bg-destructive/10' : ''}
110
115
  "
111
116
  >
112
- {#if value}
113
- <EnumBadge {value} enum={enumOptions} />
117
+ {#if value != null && enumOptions}
118
+ <EnumBadge value={String(value)} enum={enumOptions} />
119
+ {:else if value != null}
120
+ {value}
114
121
  {:else}
115
- NULL
122
+ <span class="text-muted-foreground">{ui?.placeholder ?? "NULL"}</span>
116
123
  {/if}
117
124
  </Select.Trigger>
118
125
  <Select.Content>
119
126
  <Select.Group>
120
- {#each enumOptions as option}
121
- <Select.Item value={option.value} label={option.value}>
122
- <EnumBadge value={option.value} enum={enumOptions} />
127
+ {#each rawEnum as option}
128
+ {@const optionValue = typeof option === "object" ? String(option.value) : String(option)}
129
+ <Select.Item value={optionValue} label={optionValue}>
130
+ {#if enumOptions}
131
+ <EnumBadge value={optionValue} enum={enumOptions} />
132
+ {:else}
133
+ {optionValue}
134
+ {/if}
123
135
  </Select.Item>
124
136
  {/each}
125
137
  </Select.Group>
126
138
  </Select.Content>
127
139
  </Select.Root>
128
140
  {:else if field.type === "string"}
129
- <!-- if the string has a validator of type enum -->
130
- {#if field.validators && field.validators.enum}
131
- <Select.Root
132
- type="single"
133
- onValueChange={(newValue) => {
134
- value = newValue;
135
- }}
136
- >
137
- <Select.Trigger
138
- placeholder={ui?.placeholder ? ui.placeholder : "NULL"}
139
- class="
140
- h-9 w-full bg-muted/30 pr-8
141
- {destructive ? 'border-destructive bg-destructive/10' : ''}
142
- "
143
- >
144
- {value ? value : "NULL"}
145
- </Select.Trigger>
146
- <Select.Content>
147
- <Select.Group>
148
- {#each field.validators.enum as option}
149
- <Select.Item value={option} label={option} />
150
- {/each}
151
- </Select.Group>
152
- </Select.Content>
153
- </Select.Root>
154
- {:else}
155
- <Input
156
- placeholder={ui?.placeholder ? ui.placeholder : "NULL"}
157
- type="text"
158
- class="
159
- bg-muted/30 text-xs
160
- {destructive ? 'border-destructive bg-destructive/10' : ''}
161
- "
162
- bind:value
163
- />
164
- {/if}
141
+ <Input
142
+ placeholder={ui?.placeholder ? ui.placeholder : "NULL"}
143
+ type="text"
144
+ class="
145
+ bg-muted/30 text-xs
146
+ {destructive ? 'border-destructive bg-destructive/10' : ''}
147
+ "
148
+ bind:value
149
+ />
165
150
  {:else if field.type === "text"}
166
151
  <Textarea
167
152
  placeholder={ui?.placeholder ? ui.placeholder : value === "" ? "EMPTY STRING" : "NULL"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lobb-js/studio",
3
3
  "license": "UNLICENSED",
4
- "version": "0.14.0",
4
+ "version": "0.15.0",
5
5
  "type": "module",
6
6
  "publishConfig": {
7
7
  "access": "public"
@@ -42,7 +42,7 @@
42
42
  "postpublish": "./scripts/postpublish.sh"
43
43
  },
44
44
  "devDependencies": {
45
- "@lobb-js/core": "^0.19.0",
45
+ "@lobb-js/core": "^0.21.0",
46
46
  "@chromatic-com/storybook": "^4.1.2",
47
47
  "@storybook/addon-a11y": "^10.0.1",
48
48
  "@storybook/addon-docs": "^10.0.1",
@@ -8,26 +8,47 @@
8
8
 
9
9
  const { value, enum: enumOptions }: Props = $props();
10
10
 
11
- const levelClasses: Record<string, string> = {
12
- success: "bg-green-100 text-green-700 border-green-200",
13
- warning: "bg-yellow-100 text-yellow-700 border-yellow-300",
14
- danger: "bg-red-100 text-red-700 border-red-200",
15
- info: "bg-blue-100 text-blue-700 border-blue-200",
16
- neutral: "bg-gray-100 text-gray-600 border-gray-200",
17
- muted: "bg-gray-50 text-gray-400 border-gray-100",
11
+ const colorClasses: Record<string, string> = {
12
+ red: "bg-red-100 text-red-700 border-red-200 dark:bg-red-900/30 dark:text-red-300 dark:border-red-800",
13
+ rose: "bg-rose-100 text-rose-700 border-rose-200 dark:bg-rose-900/30 dark:text-rose-300 dark:border-rose-800",
14
+ pink: "bg-pink-100 text-pink-700 border-pink-200 dark:bg-pink-900/30 dark:text-pink-300 dark:border-pink-800",
15
+ fuchsia: "bg-fuchsia-100 text-fuchsia-700 border-fuchsia-200 dark:bg-fuchsia-900/30 dark:text-fuchsia-300 dark:border-fuchsia-800",
16
+ purple: "bg-purple-100 text-purple-700 border-purple-200 dark:bg-purple-900/30 dark:text-purple-300 dark:border-purple-800",
17
+ violet: "bg-violet-100 text-violet-700 border-violet-200 dark:bg-violet-900/30 dark:text-violet-300 dark:border-violet-800",
18
+ indigo: "bg-indigo-100 text-indigo-700 border-indigo-200 dark:bg-indigo-900/30 dark:text-indigo-300 dark:border-indigo-800",
19
+ blue: "bg-blue-100 text-blue-700 border-blue-200 dark:bg-blue-900/30 dark:text-blue-300 dark:border-blue-800",
20
+ sky: "bg-sky-100 text-sky-700 border-sky-200 dark:bg-sky-900/30 dark:text-sky-300 dark:border-sky-800",
21
+ cyan: "bg-cyan-100 text-cyan-700 border-cyan-200 dark:bg-cyan-900/30 dark:text-cyan-300 dark:border-cyan-800",
22
+ teal: "bg-teal-100 text-teal-700 border-teal-200 dark:bg-teal-900/30 dark:text-teal-300 dark:border-teal-800",
23
+ emerald: "bg-emerald-100 text-emerald-700 border-emerald-200 dark:bg-emerald-900/30 dark:text-emerald-300 dark:border-emerald-800",
24
+ green: "bg-green-100 text-green-700 border-green-200 dark:bg-green-900/30 dark:text-green-300 dark:border-green-800",
25
+ lime: "bg-lime-100 text-lime-700 border-lime-200 dark:bg-lime-900/30 dark:text-lime-300 dark:border-lime-800",
26
+ yellow: "bg-yellow-100 text-yellow-700 border-yellow-300 dark:bg-yellow-900/30 dark:text-yellow-300 dark:border-yellow-800",
27
+ amber: "bg-amber-100 text-amber-700 border-amber-200 dark:bg-amber-900/30 dark:text-amber-300 dark:border-amber-800",
28
+ orange: "bg-orange-100 text-orange-700 border-orange-200 dark:bg-orange-900/30 dark:text-orange-300 dark:border-orange-800",
29
+ slate: "bg-slate-100 text-slate-600 border-slate-200 dark:bg-slate-800/50 dark:text-slate-300 dark:border-slate-700",
30
+ zinc: "bg-zinc-100 text-zinc-600 border-zinc-200 dark:bg-zinc-800/50 dark:text-zinc-300 dark:border-zinc-700",
31
+ gray: "bg-gray-100 text-gray-600 border-gray-200 dark:bg-gray-800/50 dark:text-gray-300 dark:border-gray-700",
32
+ stone: "bg-stone-100 text-stone-600 border-stone-200 dark:bg-stone-800/50 dark:text-stone-300 dark:border-stone-700",
33
+ neutral: "bg-neutral-100 text-neutral-600 border-neutral-200 dark:bg-neutral-800/50 dark:text-neutral-300 dark:border-neutral-700",
18
34
  };
19
35
 
20
36
  const normalizedOptions = $derived(
21
- (enumOptions as Array<string | EnumOption>).map((e) =>
22
- typeof e === "string" ? { value: e, level: "neutral" as const } : e,
37
+ (enumOptions as Array<string | number | EnumOption>).map((e) =>
38
+ typeof e === "object" ? e : { value: e, color: undefined, description: undefined },
23
39
  ),
24
40
  );
25
41
 
26
- const enumOption = $derived(normalizedOptions.find((e) => e.value === value));
42
+ const enumOption = $derived(normalizedOptions.find((e) => String(e.value) === String(value)));
27
43
  </script>
28
44
 
29
45
  {#if enumOption}
30
- <span class="px-2 py-0.5 rounded-full text-xs font-medium border {levelClasses[enumOption.level]}">
31
- {value}
46
+ <span class="flex items-center gap-1.5">
47
+ <span class="px-2 py-0.5 rounded-full text-xs font-medium border {enumOption.color ? colorClasses[enumOption.color] : colorClasses['gray']}">
48
+ {enumOption.value}
49
+ </span>
50
+ {#if enumOption.description}
51
+ <span class="text-xs text-muted-foreground">{enumOption.description}</span>
52
+ {/if}
32
53
  </span>
33
54
  {/if}
@@ -93,75 +93,60 @@
93
93
  {destructive}
94
94
  />
95
95
  </ExtensionsComponents>
96
- {:else if field.type === "string" && field.enum}
97
- {@const rawEnum = field.enum as (string | EnumOption)[]}
98
- {@const enumOptions = rawEnum.map((e): EnumOption => typeof e === "string" ? { value: e, level: "neutral" } : e)}
96
+ {:else if field.enum}
97
+ {@const rawEnum = field.enum as (string | number | EnumOption)[]}
98
+ {@const isEnumOption = rawEnum.length > 0 && typeof rawEnum[0] === "object"}
99
+ {@const enumOptions = isEnumOption ? rawEnum as EnumOption[] : undefined}
99
100
  <Select.Root
100
101
  type="single"
101
- onValueChange={(newValue) => {
102
- value = newValue;
103
- }}
102
+ bind:value={
103
+ () => value != null ? String(value) : null,
104
+ (v) => {
105
+ if (v == null) { value = null; return; }
106
+ const isNumeric = field.type === "integer" || field.type === "long" || field.type === "decimal" || field.type === "float";
107
+ value = isNumeric ? Number(v) : v;
108
+ }
109
+ }
104
110
  >
105
111
  <Select.Trigger
106
- placeholder={ui?.placeholder ? ui.placeholder : "NULL"}
107
112
  class="
108
113
  h-9 w-full bg-muted/30 pr-8
109
114
  {destructive ? 'border-destructive bg-destructive/10' : ''}
110
115
  "
111
116
  >
112
- {#if value}
113
- <EnumBadge {value} enum={enumOptions} />
117
+ {#if value != null && enumOptions}
118
+ <EnumBadge value={String(value)} enum={enumOptions} />
119
+ {:else if value != null}
120
+ {value}
114
121
  {:else}
115
- NULL
122
+ <span class="text-muted-foreground">{ui?.placeholder ?? "NULL"}</span>
116
123
  {/if}
117
124
  </Select.Trigger>
118
125
  <Select.Content>
119
126
  <Select.Group>
120
- {#each enumOptions as option}
121
- <Select.Item value={option.value} label={option.value}>
122
- <EnumBadge value={option.value} enum={enumOptions} />
127
+ {#each rawEnum as option}
128
+ {@const optionValue = typeof option === "object" ? String(option.value) : String(option)}
129
+ <Select.Item value={optionValue} label={optionValue}>
130
+ {#if enumOptions}
131
+ <EnumBadge value={optionValue} enum={enumOptions} />
132
+ {:else}
133
+ {optionValue}
134
+ {/if}
123
135
  </Select.Item>
124
136
  {/each}
125
137
  </Select.Group>
126
138
  </Select.Content>
127
139
  </Select.Root>
128
140
  {:else if field.type === "string"}
129
- <!-- if the string has a validator of type enum -->
130
- {#if field.validators && field.validators.enum}
131
- <Select.Root
132
- type="single"
133
- onValueChange={(newValue) => {
134
- value = newValue;
135
- }}
136
- >
137
- <Select.Trigger
138
- placeholder={ui?.placeholder ? ui.placeholder : "NULL"}
139
- class="
140
- h-9 w-full bg-muted/30 pr-8
141
- {destructive ? 'border-destructive bg-destructive/10' : ''}
142
- "
143
- >
144
- {value ? value : "NULL"}
145
- </Select.Trigger>
146
- <Select.Content>
147
- <Select.Group>
148
- {#each field.validators.enum as option}
149
- <Select.Item value={option} label={option} />
150
- {/each}
151
- </Select.Group>
152
- </Select.Content>
153
- </Select.Root>
154
- {:else}
155
- <Input
156
- placeholder={ui?.placeholder ? ui.placeholder : "NULL"}
157
- type="text"
158
- class="
159
- bg-muted/30 text-xs
160
- {destructive ? 'border-destructive bg-destructive/10' : ''}
161
- "
162
- bind:value
163
- />
164
- {/if}
141
+ <Input
142
+ placeholder={ui?.placeholder ? ui.placeholder : "NULL"}
143
+ type="text"
144
+ class="
145
+ bg-muted/30 text-xs
146
+ {destructive ? 'border-destructive bg-destructive/10' : ''}
147
+ "
148
+ bind:value
149
+ />
165
150
  {:else if field.type === "text"}
166
151
  <Textarea
167
152
  placeholder={ui?.placeholder ? ui.placeholder : value === "" ? "EMPTY STRING" : "NULL"}