@webstudio-is/sdk-components-react-radix 0.85.0 → 0.87.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 (149) hide show
  1. package/lib/__generated__/accordion.props.js +2134 -0
  2. package/lib/__generated__/button.props.js +454 -0
  3. package/lib/__generated__/dialog.props.js +0 -7
  4. package/lib/__generated__/input.props.js +451 -0
  5. package/lib/__generated__/label.props.js +421 -0
  6. package/lib/__generated__/popover.props.js +0 -7
  7. package/lib/__generated__/sheet.props.js +0 -7
  8. package/lib/__generated__/textarea.props.js +431 -0
  9. package/lib/__generated__/tooltip.props.js +0 -7
  10. package/lib/accordion.js +51 -0
  11. package/lib/accordion.ws.js +243 -0
  12. package/lib/button.js +8 -0
  13. package/lib/button.ws.js +133 -0
  14. package/lib/cjs/__generated__/accordion.props.js +2154 -0
  15. package/lib/cjs/__generated__/button.props.js +474 -0
  16. package/lib/cjs/__generated__/dialog.props.js +0 -7
  17. package/lib/cjs/__generated__/input.props.js +471 -0
  18. package/lib/cjs/__generated__/label.props.js +441 -0
  19. package/lib/cjs/__generated__/popover.props.js +0 -7
  20. package/lib/cjs/__generated__/sheet.props.js +0 -7
  21. package/lib/cjs/__generated__/textarea.props.js +451 -0
  22. package/lib/cjs/__generated__/tooltip.props.js +0 -7
  23. package/lib/cjs/accordion.js +60 -0
  24. package/lib/cjs/accordion.ws.js +261 -0
  25. package/lib/cjs/button.js +28 -0
  26. package/lib/cjs/button.ws.js +160 -0
  27. package/lib/cjs/collapsible.js +2 -16
  28. package/lib/cjs/collapsible.ws.js +1 -8
  29. package/lib/cjs/components.js +14 -0
  30. package/lib/cjs/dialog.js +38 -6
  31. package/lib/cjs/dialog.ws.js +15 -26
  32. package/lib/cjs/hooks.js +15 -1
  33. package/lib/cjs/input.js +28 -0
  34. package/lib/cjs/input.ws.js +103 -0
  35. package/lib/cjs/label.js +37 -0
  36. package/lib/cjs/label.ws.js +74 -0
  37. package/lib/cjs/metas.js +14 -0
  38. package/lib/cjs/popover.js +37 -5
  39. package/lib/cjs/popover.ws.js +15 -18
  40. package/lib/cjs/props.js +14 -0
  41. package/lib/cjs/sheet.js +34 -1
  42. package/lib/cjs/sheet.ws.js +33 -19
  43. package/lib/cjs/tabs.js +20 -1
  44. package/lib/cjs/tabs.ws.js +3 -25
  45. package/lib/cjs/textarea.js +28 -0
  46. package/lib/cjs/textarea.ws.js +98 -0
  47. package/lib/cjs/theme/tailwind-classes.js +186 -23
  48. package/lib/cjs/theme/tailwind-colors.js +10 -1
  49. package/lib/cjs/tooltip.js +36 -4
  50. package/lib/cjs/tooltip.ws.js +15 -18
  51. package/lib/collapsible.js +2 -16
  52. package/lib/collapsible.ws.js +1 -8
  53. package/lib/components.js +20 -0
  54. package/lib/dialog.js +38 -6
  55. package/lib/dialog.ws.js +15 -26
  56. package/lib/hooks.js +15 -1
  57. package/lib/input.js +8 -0
  58. package/lib/input.ws.js +75 -0
  59. package/lib/label.js +9 -0
  60. package/lib/label.ws.js +46 -0
  61. package/lib/metas.js +20 -0
  62. package/lib/popover.js +37 -5
  63. package/lib/popover.ws.js +15 -18
  64. package/lib/props.js +20 -0
  65. package/lib/sheet.js +34 -1
  66. package/lib/sheet.ws.js +33 -19
  67. package/lib/tabs.js +24 -2
  68. package/lib/tabs.ws.js +3 -25
  69. package/lib/textarea.js +8 -0
  70. package/lib/textarea.ws.js +70 -0
  71. package/lib/theme/tailwind-classes.js +191 -24
  72. package/lib/theme/tailwind-colors.js +10 -1
  73. package/lib/tooltip.js +36 -4
  74. package/lib/tooltip.ws.js +15 -18
  75. package/lib/types/__generated__/accordion.props.d.ts +6 -0
  76. package/lib/types/__generated__/button.props.d.ts +2 -0
  77. package/lib/types/__generated__/input.props.d.ts +2 -0
  78. package/lib/types/__generated__/label.props.d.ts +2 -0
  79. package/lib/types/__generated__/textarea.props.d.ts +2 -0
  80. package/lib/types/accordion.d.ts +12 -0
  81. package/lib/types/accordion.ws.d.ts +11 -0
  82. package/lib/types/button.d.ts +7 -0
  83. package/lib/types/button.stories.d.ts +20 -0
  84. package/lib/types/button.ws.d.ts +7 -0
  85. package/lib/types/components.d.ts +5 -0
  86. package/lib/types/dialog.d.ts +5 -11
  87. package/lib/types/input.d.ts +2 -0
  88. package/lib/types/input.stories.d.ts +20 -0
  89. package/lib/types/input.ws.d.ts +3 -0
  90. package/lib/types/label.d.ts +3 -0
  91. package/lib/types/label.stories.d.ts +9 -0
  92. package/lib/types/label.ws.d.ts +3 -0
  93. package/lib/types/metas.d.ts +5 -0
  94. package/lib/types/popover.d.ts +4 -10
  95. package/lib/types/props.d.ts +5 -0
  96. package/lib/types/sheet.d.ts +4 -4
  97. package/lib/types/tabs.d.ts +2 -0
  98. package/lib/types/textarea.d.ts +2 -0
  99. package/lib/types/textarea.stories.d.ts +14 -0
  100. package/lib/types/textarea.ws.d.ts +3 -0
  101. package/lib/types/theme/tailwind-classes.d.ts +16 -5
  102. package/lib/types/theme/tailwind-colors.d.ts +9 -0
  103. package/lib/types/tooltip.d.ts +3 -9
  104. package/package.json +9 -7
  105. package/src/__generated__/accordion.props.ts +2382 -0
  106. package/src/__generated__/button.props.ts +503 -0
  107. package/src/__generated__/dialog.props.ts +0 -7
  108. package/src/__generated__/input.props.ts +500 -0
  109. package/src/__generated__/label.props.ts +470 -0
  110. package/src/__generated__/popover.props.ts +0 -7
  111. package/src/__generated__/sheet.props.ts +0 -7
  112. package/src/__generated__/textarea.props.ts +480 -0
  113. package/src/__generated__/tooltip.props.ts +0 -7
  114. package/src/accordion.stories.tsx +21 -0
  115. package/src/accordion.tsx +81 -0
  116. package/src/accordion.ws.ts +270 -0
  117. package/src/button.stories.ts +35 -0
  118. package/src/button.tsx +25 -0
  119. package/src/button.ws.ts +155 -0
  120. package/src/collapsible.tsx +2 -16
  121. package/src/collapsible.ws.ts +1 -8
  122. package/src/components.ts +11 -0
  123. package/src/dialog.stories.tsx +21 -0
  124. package/src/dialog.tsx +50 -24
  125. package/src/dialog.ws.tsx +15 -26
  126. package/src/hooks.ts +15 -1
  127. package/src/input.stories.ts +31 -0
  128. package/src/input.tsx +12 -0
  129. package/src/input.ws.ts +78 -0
  130. package/src/label.stories.ts +22 -0
  131. package/src/label.tsx +15 -0
  132. package/src/label.ws.ts +48 -0
  133. package/src/metas.ts +11 -0
  134. package/src/popover.stories.tsx +21 -0
  135. package/src/popover.tsx +49 -23
  136. package/src/popover.ws.tsx +15 -18
  137. package/src/props.ts +11 -0
  138. package/src/sheet.tsx +39 -0
  139. package/src/sheet.ws.tsx +33 -19
  140. package/src/tabs.tsx +32 -1
  141. package/src/tabs.ws.ts +1 -23
  142. package/src/textarea.stories.ts +27 -0
  143. package/src/textarea.tsx +12 -0
  144. package/src/textarea.ws.ts +74 -0
  145. package/src/theme/tailwind-classes.ts +233 -38
  146. package/src/theme/tailwind-colors.ts +9 -16
  147. package/src/tooltip.stories.tsx +21 -0
  148. package/src/tooltip.tsx +46 -20
  149. package/src/tooltip.ws.tsx +15 -18
package/src/sheet.ws.tsx CHANGED
@@ -25,6 +25,7 @@ import {
25
25
  import { div, nav, button, h2, p } from "@webstudio-is/react-sdk/css-normalize";
26
26
  import type { SheetContent } from "./sheet";
27
27
  import type { ComponentProps } from "react";
28
+ import { template as buttonTemplate } from "./button.ws";
28
29
 
29
30
  type ContentTags = NonNullable<ComponentProps<typeof SheetContent>["tag"]>;
30
31
 
@@ -53,7 +54,6 @@ const descriptionPresetStyle = {
53
54
  export const metaSheetTrigger: WsComponentMeta = {
54
55
  category: "hidden",
55
56
  type: "container",
56
- label: "Sheet Trigger",
57
57
  icon: TriggerIcon,
58
58
  stylable: false,
59
59
  detachable: false,
@@ -62,7 +62,6 @@ export const metaSheetTrigger: WsComponentMeta = {
62
62
  export const metaSheetContent: WsComponentMeta = {
63
63
  category: "hidden",
64
64
  type: "container",
65
- label: "Sheet Content",
66
65
  icon: ContentIcon,
67
66
  detachable: false,
68
67
  presetStyle: contentPresetStyle,
@@ -78,7 +77,6 @@ export const metaSheetOverlay: WsComponentMeta = {
78
77
  category: "hidden",
79
78
  type: "container",
80
79
  presetStyle,
81
- label: "Sheet Overlay",
82
80
  icon: OverlayIcon,
83
81
  detachable: false,
84
82
  };
@@ -87,7 +85,6 @@ export const metaSheetTitle: WsComponentMeta = {
87
85
  category: "hidden",
88
86
  type: "container",
89
87
  presetStyle: titlePresetStyle,
90
- label: "Sheet Title",
91
88
  icon: HeadingIcon,
92
89
  };
93
90
 
@@ -95,7 +92,6 @@ export const metaSheetDescription: WsComponentMeta = {
95
92
  category: "hidden",
96
93
  type: "container",
97
94
  presetStyle: descriptionPresetStyle,
98
- label: "Sheet Description",
99
95
  icon: TextIcon,
100
96
  };
101
97
 
@@ -103,7 +99,6 @@ export const metaSheetClose: WsComponentMeta = {
103
99
  category: "hidden",
104
100
  type: "container",
105
101
  presetStyle: buttonPresetStyle,
106
- label: "Sheet Close",
107
102
  icon: ButtonElementIcon,
108
103
  };
109
104
 
@@ -119,7 +114,6 @@ export const metaSheet: WsComponentMeta = {
119
114
  category: "radix",
120
115
 
121
116
  type: "container",
122
- label: "Sheet",
123
117
  icon: HamburgerMenuIcon,
124
118
  order: 15,
125
119
  stylable: false,
@@ -128,27 +122,47 @@ export const metaSheet: WsComponentMeta = {
128
122
  type: "instance",
129
123
  component: "Sheet",
130
124
  dataSources: {
131
- // We don't have support for boolean or undefined, instead of binding on open we bind on a string
132
- isOpen: { type: "variable", initialValue: "initial" },
125
+ sheetOpen: { type: "variable", initialValue: false },
133
126
  },
134
127
  props: [
135
128
  {
136
129
  type: "dataSource",
137
- name: "isOpen",
138
- dataSourceName: "isOpen",
130
+ name: "open",
131
+ dataSourceName: "sheetOpen",
132
+ },
133
+ {
134
+ name: "onOpenChange",
135
+ type: "action",
136
+ value: [
137
+ { type: "execute", args: ["open"], code: `sheetOpen = open` },
138
+ ],
139
139
  },
140
140
  ],
141
141
  children: [
142
142
  {
143
143
  type: "instance",
144
144
  component: "SheetTrigger",
145
- children: [
146
- {
147
- type: "instance",
148
- component: "Button",
149
- children: [{ type: "text", value: "Button" }],
150
- },
151
- ],
145
+ children: buttonTemplate({
146
+ props: [
147
+ { name: "variant", type: "string", value: "ghost" },
148
+ { name: "size", type: "string", value: "icon" },
149
+ ],
150
+ children: [
151
+ {
152
+ type: "instance",
153
+ component: "HtmlEmbed",
154
+ label: "Hamburger Menu Svg",
155
+ props: [
156
+ {
157
+ type: "string",
158
+ name: "code",
159
+ value: HamburgerMenuIcon,
160
+ },
161
+ ],
162
+ children: [],
163
+ },
164
+ ],
165
+ }),
152
166
  },
153
167
  {
154
168
  type: "instance",
@@ -293,7 +307,7 @@ export const metaSheet: WsComponentMeta = {
293
307
 
294
308
  export const propsMetaSheet: WsComponentPropsMeta = {
295
309
  props: propsSheet,
296
- initialProps: ["isOpen", "modal"],
310
+ initialProps: ["open", "modal"],
297
311
  };
298
312
 
299
313
  export const propsMetaSheetTrigger: WsComponentPropsMeta = {
package/src/tabs.tsx CHANGED
@@ -10,7 +10,11 @@ import {
10
10
  Children,
11
11
  } from "react";
12
12
  import { Root, List, Trigger, Content } from "@radix-ui/react-tabs";
13
- import { getIndexWithinAncestorFromComponentProps } from "@webstudio-is/react-sdk";
13
+ import {
14
+ getClosestInstance,
15
+ getIndexWithinAncestorFromComponentProps,
16
+ type Hook,
17
+ } from "@webstudio-is/react-sdk";
14
18
 
15
19
  export const Tabs: ForwardRefExoticComponent<
16
20
  Omit<ComponentPropsWithRef<typeof Root>, "asChild" | "defaultValue">
@@ -44,3 +48,30 @@ export const TabsContent = forwardRef<
44
48
  const index = getIndexWithinAncestorFromComponentProps(props);
45
49
  return <Content ref={ref} value={value ?? index} {...props} />;
46
50
  });
51
+
52
+ /* BUILDER HOOKS */
53
+
54
+ const namespace = "@webstudio-is/sdk-components-react-radix";
55
+
56
+ // For each TabsContent component within the selection,
57
+ // we identify its closest parent Tabs component
58
+ // and update its open prop bound to variable.
59
+ export const hooksTabs: Hook = {
60
+ onNavigatorSelect: (context, event) => {
61
+ for (const instance of event.instancePath) {
62
+ if (instance.component === `${namespace}:TabsContent`) {
63
+ const tabs = getClosestInstance(
64
+ event.instancePath,
65
+ instance,
66
+ `${namespace}:Tabs`
67
+ );
68
+ const contentValue =
69
+ context.getPropValue(instance.id, "value") ??
70
+ context.indexesWithinAncestors.get(instance.id)?.toString();
71
+ if (tabs && contentValue) {
72
+ context.setPropVariable(tabs.id, "value", contentValue);
73
+ }
74
+ }
75
+ }
76
+ },
77
+ };
package/src/tabs.ws.ts CHANGED
@@ -65,7 +65,6 @@ const tabsContentStyles: EmbedTemplateStyleDecl[] = [
65
65
  export const metaTabs: WsComponentMeta = {
66
66
  category: "radix",
67
67
  type: "container",
68
- label: "Tabs",
69
68
  icon: TabsIcon,
70
69
  presetStyle,
71
70
  template: [
@@ -81,11 +80,7 @@ export const metaTabs: WsComponentMeta = {
81
80
  name: "onValueChange",
82
81
  type: "action",
83
82
  value: [
84
- {
85
- type: "execute",
86
- args: ["value"],
87
- code: `tabsValue = value`,
88
- },
83
+ { type: "execute", args: ["value"], code: `tabsValue = value` },
89
84
  ],
90
85
  },
91
86
  ],
@@ -154,7 +149,6 @@ export const metaTabsList: WsComponentMeta = {
154
149
  category: "hidden",
155
150
  detachable: false,
156
151
  type: "container",
157
- label: "Tabs List",
158
152
  icon: HeaderIcon,
159
153
  requiredAncestors: ["Tabs"],
160
154
  presetStyle,
@@ -163,35 +157,19 @@ export const metaTabsList: WsComponentMeta = {
163
157
  export const metaTabsTrigger: WsComponentMeta = {
164
158
  category: "hidden",
165
159
  type: "container",
166
- label: "Tabs Trigger",
167
160
  icon: TriggerIcon,
168
161
  requiredAncestors: ["TabsList"],
169
162
  invalidAncestors: ["TabsTrigger"],
170
163
  indexWithinAncestor: "Tabs",
171
- template: [
172
- {
173
- type: "instance",
174
- component: "TabsTrigger",
175
- children: [{ type: "text", value: "New Tab" }],
176
- },
177
- ],
178
164
  };
179
165
 
180
166
  export const metaTabsContent: WsComponentMeta = {
181
167
  category: "hidden",
182
168
  type: "container",
183
- label: "Tabs Content",
184
169
  icon: ContentIcon,
185
170
  requiredAncestors: ["Tabs"],
186
171
  indexWithinAncestor: "Tabs",
187
172
  presetStyle,
188
- template: [
189
- {
190
- type: "instance",
191
- component: "TabsContent",
192
- children: [{ type: "text", value: "New Tab Content" }],
193
- },
194
- ],
195
173
  };
196
174
 
197
175
  export const propsMetaTabs: WsComponentPropsMeta = {
@@ -0,0 +1,27 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { renderComponentTemplate } from "@webstudio-is/react-sdk";
3
+ import { Textarea as TextareaPrimitive } from "./textarea";
4
+ import * as baseComponents from "@webstudio-is/sdk-components-react";
5
+ import * as baseMetas from "@webstudio-is/sdk-components-react/metas";
6
+ import * as radixComponents from "./components";
7
+ import * as radixMetas from "./metas";
8
+
9
+ export default {
10
+ title: "Components/Textarea",
11
+ component: TextareaPrimitive,
12
+ argTypes: {
13
+ placeholder: {
14
+ type: "string",
15
+ },
16
+ },
17
+ } satisfies Meta<typeof TextareaPrimitive>;
18
+
19
+ export const Textarea: StoryObj<typeof TextareaPrimitive> = {
20
+ render: (props) =>
21
+ renderComponentTemplate({
22
+ name: "Textarea",
23
+ props: { ...props },
24
+ components: { ...baseComponents, ...radixComponents },
25
+ metas: { ...baseMetas, ...radixMetas },
26
+ }),
27
+ };
@@ -0,0 +1,12 @@
1
+ /* eslint-disable react/display-name */
2
+ // We can't use .displayName until this is merged https://github.com/styleguidist/react-docgen-typescript/pull/449
3
+
4
+ import { forwardRef, type ComponentPropsWithoutRef } from "react";
5
+
6
+ export const Textarea = forwardRef<
7
+ HTMLTextAreaElement,
8
+ ComponentPropsWithoutRef<"textarea">
9
+ // Make sure children are not passed down to an input, because this will result in error.
10
+ >(({ children: _children, ...props }, ref) => {
11
+ return <textarea ref={ref} {...props} />;
12
+ });
@@ -0,0 +1,74 @@
1
+ import { FormTextAreaIcon } from "@webstudio-is/icons/svg";
2
+ import {
3
+ defaultStates,
4
+ type PresetStyle,
5
+ type WsComponentMeta,
6
+ type WsComponentPropsMeta,
7
+ } from "@webstudio-is/react-sdk";
8
+ import { textarea } from "@webstudio-is/react-sdk/css-normalize";
9
+ import { props } from "./__generated__/textarea.props";
10
+ import * as tc from "./theme/tailwind-classes";
11
+
12
+ const presetStyle = {
13
+ textarea,
14
+ } satisfies PresetStyle<"textarea">;
15
+
16
+ export const meta: WsComponentMeta = {
17
+ category: "radix",
18
+ type: "control",
19
+ invalidAncestors: ["Button"],
20
+ icon: FormTextAreaIcon,
21
+ presetStyle,
22
+ states: [
23
+ ...defaultStates,
24
+ { selector: ":disabled", label: "Disabled" },
25
+ { selector: "::placeholder", label: "Placeholder" },
26
+ // @todo share https://github.com/webstudio-is/webstudio-builder/issues/2102
27
+ { selector: ":valid", label: "Valid" },
28
+ { selector: ":invalid", label: "Invalid" },
29
+ { selector: ":required", label: "Required" },
30
+ { selector: ":optional", label: "Optional" },
31
+ { selector: ":enabled", label: "Enabled" },
32
+ { selector: ":read-only", label: "Read Only" },
33
+ { selector: ":read-write", label: "Read Write" },
34
+ ],
35
+ order: 1,
36
+ template: [
37
+ {
38
+ type: "instance",
39
+ component: "Textarea",
40
+ styles: [
41
+ // flex min-h-[80px] w-full rounded-md
42
+ // border border-input bg-background
43
+ // px-3 py-2 text-sm ring-offset-background
44
+ // placeholder:text-muted-foreground
45
+ // focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring
46
+ // focus-visible:ring-offset-2
47
+ // disabled:cursor-not-allowed disabled:opacity-50
48
+
49
+ tc.flex(),
50
+ tc.minH(20),
51
+ tc.w("full"),
52
+ tc.rounded("md"),
53
+ tc.border(),
54
+ tc.border("input"),
55
+ tc.bg("background"),
56
+ tc.px(3),
57
+ tc.py(2),
58
+ tc.text("sm"),
59
+ tc.state(tc.text("mutedForeground"), "::placeholder"),
60
+ tc.focusVisible(
61
+ [tc.outline("none"), tc.ring("ring", 2, "background", 2)].flat()
62
+ ),
63
+ tc.disabled([tc.cursor("not-allowed"), tc.opacity(50)].flat()),
64
+ ].flat(),
65
+
66
+ children: [],
67
+ },
68
+ ],
69
+ };
70
+
71
+ export const propsMeta: WsComponentPropsMeta = {
72
+ props,
73
+ initialProps: ["id", "name", "placeholder", "required", "autoFocus"],
74
+ };
@@ -3,7 +3,11 @@
3
3
  */
4
4
  import type { EmbedTemplateStyleDecl } from "@webstudio-is/react-sdk";
5
5
  import { theme } from "./tailwind-theme";
6
- import { parseCssValue, parseBoxShadow } from "@webstudio-is/css-data";
6
+ import {
7
+ parseCssValue,
8
+ parseBoxShadow,
9
+ StyleValue,
10
+ } from "@webstudio-is/css-data";
7
11
  import type { EvaluatedDefaultTheme } from "./radix-common-types";
8
12
 
9
13
  // https://github.com/tailwindlabs/tailwindcss/blob/master/src/css/preflight.css
@@ -106,58 +110,127 @@ type NonNumeric<T extends string> = T extends `${infer Z extends number}`
106
110
  : T;
107
111
 
108
112
  export const border = (
109
- borderWidth?: StringEnumToNumeric<keyof EvaluatedDefaultTheme["borderWidth"]>
113
+ borderWidthOrColor?:
114
+ | StringEnumToNumeric<keyof EvaluatedDefaultTheme["borderWidth"]>
115
+ | keyof EvaluatedDefaultTheme["colors"]
110
116
  ): EmbedTemplateStyleDecl[] => {
111
- const key = `${borderWidth ?? "DEFAULT"}` as const;
117
+ if (
118
+ typeof borderWidthOrColor === "number" ||
119
+ borderWidthOrColor === undefined
120
+ ) {
121
+ const key = `${borderWidthOrColor ?? "DEFAULT"}` as const;
112
122
 
113
- const valueString = theme("borderWidth")?.[key] ?? "1px";
123
+ const valueString = theme("borderWidth")?.[key] ?? "1px";
124
+
125
+ const value = parseCssValue("borderTopWidth", valueString);
126
+ return [
127
+ ...preflight(),
128
+ { property: "borderTopWidth", value },
129
+ { property: "borderRightWidth", value },
130
+ { property: "borderBottomWidth", value },
131
+ { property: "borderLeftWidth", value },
132
+ ];
133
+ }
134
+
135
+ const value = parseCssValue("color", theme("colors")[borderWidthOrColor]);
114
136
 
115
- const value = parseCssValue("borderTopWidth", valueString);
116
137
  return [
117
- ...preflight(),
118
- { property: "borderTopWidth", value },
119
- { property: "borderRightWidth", value },
120
- { property: "borderBottomWidth", value },
121
- { property: "borderLeftWidth", value },
138
+ {
139
+ property: "borderTopColor",
140
+ value,
141
+ },
142
+ {
143
+ property: "borderRightColor",
144
+ value,
145
+ },
146
+ {
147
+ property: "borderBottomColor",
148
+ value,
149
+ },
150
+ {
151
+ property: "borderLeftColor",
152
+ value,
153
+ },
122
154
  ];
123
155
  };
124
156
 
125
- export const px = (
126
- padding:
127
- | StringEnumToNumeric<keyof EvaluatedDefaultTheme["padding"]>
128
- | NonNumeric<keyof EvaluatedDefaultTheme["padding"]>
157
+ export const borderB = (
158
+ borderWidthOrColor?:
159
+ | StringEnumToNumeric<keyof EvaluatedDefaultTheme["borderWidth"]>
160
+ | keyof EvaluatedDefaultTheme["colors"]
129
161
  ): EmbedTemplateStyleDecl[] => {
130
- const key = `${padding}` as const;
131
- const valueString = theme("padding")?.[key] ?? "0";
132
- const value = parseCssValue("paddingLeft", valueString);
162
+ let widthValue: StyleValue = { type: "unit", value: 1, unit: "number" };
163
+ let colorValue: StyleValue = parseCssValue(
164
+ "color",
165
+ theme("colors")["border"]
166
+ );
167
+ if (
168
+ typeof borderWidthOrColor === "number" ||
169
+ borderWidthOrColor === undefined
170
+ ) {
171
+ const key = `${borderWidthOrColor ?? "DEFAULT"}` as const;
172
+ const valueString = theme("borderWidth")[key] ?? "1px";
173
+ widthValue = parseCssValue("borderTopWidth", valueString);
174
+ } else {
175
+ colorValue = parseCssValue("color", theme("colors")[borderWidthOrColor]);
176
+ }
133
177
 
134
178
  return [
135
- { property: "paddingLeft", value },
136
- { property: "paddingRight", value },
179
+ {
180
+ property: "borderBottomWidth",
181
+ value: widthValue,
182
+ },
183
+ {
184
+ property: "borderBottomStyle",
185
+ value: { type: "keyword", value: "solid" },
186
+ },
187
+ {
188
+ property: "borderBottomColor",
189
+ value: colorValue,
190
+ },
137
191
  ];
138
192
  };
139
193
 
140
- export const py = (
141
- padding:
142
- | StringEnumToNumeric<keyof EvaluatedDefaultTheme["padding"]>
143
- | NonNumeric<keyof EvaluatedDefaultTheme["padding"]>
144
- ): EmbedTemplateStyleDecl[] => {
145
- const key = `${padding}` as const;
146
- const valueString = theme("padding")[key];
147
- const value = parseCssValue("paddingTop", valueString);
194
+ const paddingProperty =
195
+ (property: "paddingTop" | "paddingRight" | "paddingBottom" | "paddingLeft") =>
196
+ (
197
+ padding:
198
+ | StringEnumToNumeric<keyof EvaluatedDefaultTheme["padding"]>
199
+ | NonNumeric<keyof EvaluatedDefaultTheme["padding"]>
200
+ ): EmbedTemplateStyleDecl[] => {
201
+ const key = `${padding}` as const;
202
+ const valueString = theme("padding")?.[key] ?? "0";
203
+ const value = parseCssValue(property, valueString);
148
204
 
149
- return [
150
- { property: "paddingTop", value },
151
- { property: "paddingBottom", value },
152
- ];
205
+ return [{ property, value }];
206
+ };
207
+
208
+ export const pt: ReturnType<typeof paddingProperty> = (padding) => {
209
+ return paddingProperty("paddingTop")(padding);
153
210
  };
154
211
 
155
- export const p = (
156
- padding:
157
- | StringEnumToNumeric<keyof EvaluatedDefaultTheme["padding"]>
158
- | NonNumeric<keyof EvaluatedDefaultTheme["padding"]>
159
- ): EmbedTemplateStyleDecl[] => {
160
- return [...px(padding), ...py(padding)];
212
+ export const pb: ReturnType<typeof paddingProperty> = (padding) => {
213
+ return paddingProperty("paddingBottom")(padding);
214
+ };
215
+
216
+ export const pl: ReturnType<typeof paddingProperty> = (padding) => {
217
+ return paddingProperty("paddingLeft")(padding);
218
+ };
219
+
220
+ export const pr: ReturnType<typeof paddingProperty> = (padding) => {
221
+ return paddingProperty("paddingRight")(padding);
222
+ };
223
+
224
+ export const px: ReturnType<typeof paddingProperty> = (padding) => {
225
+ return [pl(padding), pr(padding)].flat();
226
+ };
227
+
228
+ export const py: ReturnType<typeof paddingProperty> = (padding) => {
229
+ return [pt(padding), pb(padding)].flat();
230
+ };
231
+
232
+ export const p: ReturnType<typeof paddingProperty> = (padding) => {
233
+ return [px(padding), py(padding)].flat();
161
234
  };
162
235
 
163
236
  const marginProperty =
@@ -226,6 +299,16 @@ export const h = (
226
299
  return [{ property: "height", value }];
227
300
  };
228
301
 
302
+ export const minH = (
303
+ spacing: StringEnumToNumeric<keyof EvaluatedDefaultTheme["height"]>
304
+ ): EmbedTemplateStyleDecl[] => {
305
+ const key = `${spacing}` as const;
306
+ const valueString = theme("height")?.[key] ?? "0";
307
+ const value = parseCssValue("minHeight", valueString);
308
+
309
+ return [{ property: "minHeight", value }];
310
+ };
311
+
229
312
  export const opacity = (
230
313
  opacity: StringEnumToNumeric<keyof EvaluatedDefaultTheme["opacity"]>
231
314
  ): EmbedTemplateStyleDecl[] => {
@@ -241,6 +324,20 @@ export const opacity = (
241
324
  ];
242
325
  };
243
326
 
327
+ export const cursor = (
328
+ cursor: keyof EvaluatedDefaultTheme["cursor"]
329
+ ): EmbedTemplateStyleDecl[] => {
330
+ const valueString = theme("cursor")?.[cursor] ?? "auto";
331
+ const value = parseCssValue("cursor", valueString);
332
+
333
+ return [
334
+ {
335
+ property: "cursor",
336
+ value,
337
+ },
338
+ ];
339
+ };
340
+
244
341
  export const maxW = (
245
342
  spacing:
246
343
  | StringEnumToNumeric<keyof EvaluatedDefaultTheme["maxWidth"]>
@@ -396,11 +493,83 @@ export const inlineFlex = (): EmbedTemplateStyleDecl[] => {
396
493
  const flexDirection = { row: "row", col: "column" } as const;
397
494
  type FlexDirection = keyof typeof flexDirection;
398
495
 
399
- export const flex = (flexParam?: FlexDirection): EmbedTemplateStyleDecl[] => {
496
+ type FlexSizing = 1 | "auto" | "initial" | "none";
497
+
498
+ export const flex = (
499
+ flexParam?: FlexDirection | FlexSizing
500
+ ): EmbedTemplateStyleDecl[] => {
400
501
  if (flexParam === undefined) {
401
502
  return [{ property: "display", value: { type: "keyword", value: "flex" } }];
402
503
  }
403
504
 
505
+ if (flexParam === 1) {
506
+ return [
507
+ {
508
+ property: "flexGrow",
509
+ value: { type: "unit", value: 1, unit: "number" },
510
+ },
511
+ {
512
+ property: "flexShrink",
513
+ value: { type: "unit", value: 1, unit: "number" },
514
+ },
515
+ {
516
+ property: "flexBasis",
517
+ value: { type: "unit", value: 0, unit: "%" },
518
+ },
519
+ ];
520
+ }
521
+
522
+ if (flexParam === "auto") {
523
+ return [
524
+ {
525
+ property: "flexGrow",
526
+ value: { type: "unit", value: 1, unit: "number" },
527
+ },
528
+ {
529
+ property: "flexShrink",
530
+ value: { type: "unit", value: 1, unit: "number" },
531
+ },
532
+ {
533
+ property: "flexBasis",
534
+ value: { type: "keyword", value: "auto" },
535
+ },
536
+ ];
537
+ }
538
+
539
+ if (flexParam === "initial") {
540
+ return [
541
+ {
542
+ property: "flexGrow",
543
+ value: { type: "unit", value: 0, unit: "number" },
544
+ },
545
+ {
546
+ property: "flexShrink",
547
+ value: { type: "unit", value: 1, unit: "number" },
548
+ },
549
+ {
550
+ property: "flexBasis",
551
+ value: { type: "keyword", value: "auto" },
552
+ },
553
+ ];
554
+ }
555
+
556
+ if (flexParam === "none") {
557
+ return [
558
+ {
559
+ property: "flexGrow",
560
+ value: { type: "unit", value: 0, unit: "number" },
561
+ },
562
+ {
563
+ property: "flexShrink",
564
+ value: { type: "unit", value: 0, unit: "number" },
565
+ },
566
+ {
567
+ property: "flexBasis",
568
+ value: { type: "keyword", value: "auto" },
569
+ },
570
+ ];
571
+ }
572
+
404
573
  return [
405
574
  {
406
575
  property: "flexDirection",
@@ -528,6 +697,32 @@ export const text = (
528
697
  ];
529
698
  };
530
699
 
700
+ export const underline = (): EmbedTemplateStyleDecl[] => {
701
+ return [
702
+ {
703
+ property: "textDecorationLine",
704
+ value: { type: "keyword", value: "underline" },
705
+ },
706
+ ];
707
+ };
708
+
709
+ export const underlineOffset = (
710
+ offset: StringEnumToNumeric<
711
+ keyof EvaluatedDefaultTheme["textUnderlineOffset"]
712
+ >
713
+ ): EmbedTemplateStyleDecl[] => {
714
+ const key = `${offset}` as const;
715
+ const valueString = theme("textUnderlineOffset")[key];
716
+ const value = parseCssValue("textUnderlineOffset", valueString);
717
+
718
+ return [
719
+ {
720
+ property: "textUnderlineOffset",
721
+ value,
722
+ },
723
+ ];
724
+ };
725
+
531
726
  const weights = {
532
727
  thin: "100",
533
728
  extralight: "200",