@stainless-api/ui-primitives 0.1.0-beta.6 → 0.1.0-beta.8

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @stainless-api/ui-primitives
2
2
 
3
+ ## 0.1.0-beta.8
4
+
5
+ ### Patch Changes
6
+
7
+ - d15a520: fix initialization of dropdown buttons
8
+
9
+ ## 0.1.0-beta.7
10
+
11
+ ### Patch Changes
12
+
13
+ - 34e7c61: verify dependents update
14
+
3
15
  ## 0.1.0-beta.6
4
16
 
5
17
  ### Minor Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stainless-api/ui-primitives",
3
- "version": "0.1.0-beta.6",
3
+ "version": "0.1.0-beta.8",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -10,6 +10,11 @@
10
10
  "import": "./src/index.ts",
11
11
  "require": "./src/index.ts"
12
12
  },
13
+ "./scripts": {
14
+ "types": "./src/scripts/index.ts",
15
+ "import": "./src/scripts/index.ts",
16
+ "require": "./src/scripts/index.ts"
17
+ },
13
18
  "./styles.css": "./src/styles.css"
14
19
  },
15
20
  "types": "./src/index.ts",
@@ -0,0 +1,109 @@
1
+ import clsx from 'clsx';
2
+ import { ChevronsUpDown, ExternalLink } from 'lucide-react';
3
+
4
+ function PrimaryActionText({ children }: { children?: React.ReactNode }) {
5
+ return <span data-part="primary-action-text">{children}</span>;
6
+ }
7
+
8
+ function PrimaryAction({ children }: { children?: React.ReactNode }) {
9
+ return (
10
+ <button
11
+ type="button"
12
+ data-part="primary-action"
13
+ className="stl-ui-dropdown-button__button stl-ui-dropdown-button--action"
14
+ >
15
+ {children}
16
+ </button>
17
+ );
18
+ }
19
+
20
+ function Trigger() {
21
+ return (
22
+ <button
23
+ className="stl-ui-dropdown-button__button stl-ui-dropdown-button__trigger"
24
+ aria-haspopup="listbox"
25
+ aria-expanded="false"
26
+ data-part="trigger"
27
+ >
28
+ <ChevronsUpDown size={16} />
29
+ </button>
30
+ );
31
+ }
32
+
33
+ function Menu({ children }: { children?: React.ReactNode }) {
34
+ return (
35
+ <div className="stl-ui-dropdown-button__menu" data-state="closed" data-part="menu">
36
+ {children}
37
+ </div>
38
+ );
39
+ }
40
+
41
+ function MenuItemIcon({ children }: { children?: React.ReactNode }) {
42
+ return (
43
+ <div className="stl-ui-dropdown-button__menu-item-icon" data-part="item-icon">
44
+ {children}
45
+ </div>
46
+ );
47
+ }
48
+
49
+ function MenuItemText({ children, subtle }: { children?: React.ReactNode; subtle?: boolean }) {
50
+ return (
51
+ <span
52
+ className={clsx(`stl-ui-dropdown-button__menu-item-text`, {
53
+ 'stl-ui-dropdown-button__menu-item-text--subtle': subtle,
54
+ })}
55
+ data-part="item-text"
56
+ >
57
+ {children}
58
+ </span>
59
+ );
60
+ }
61
+
62
+ function MenuItemTextSubtle({ children }: { children?: React.ReactNode }) {
63
+ return (
64
+ <span className="stl-ui-dropdown-button__menu-item-text-subtle" data-part="item-text-subtle">
65
+ {children}
66
+ </span>
67
+ );
68
+ }
69
+
70
+ function MenuItem({
71
+ children,
72
+ value,
73
+ isExternalLink,
74
+ }: {
75
+ children?: React.ReactNode;
76
+ value: string;
77
+ isExternalLink?: boolean;
78
+ }) {
79
+ return (
80
+ <div className="stl-ui-dropdown-button__menu-item" data-part="item" data-value={value}>
81
+ <div className="stl-ui-dropdown-button__menu-item-content">{children}</div>
82
+ {isExternalLink && (
83
+ <div
84
+ className="stl-ui-dropdown-button__menu-item-external-link-icon"
85
+ data-part="item-external-link-icon"
86
+ >
87
+ <ExternalLink size={16} />
88
+ </div>
89
+ )}
90
+ </div>
91
+ );
92
+ }
93
+
94
+ export function DropdownButton({ id, children }: { id: string; children?: React.ReactNode }) {
95
+ return (
96
+ <div className="stl-ui-dropdown-button stl-ui-not-prose not-content" id={id}>
97
+ {children}
98
+ </div>
99
+ );
100
+ }
101
+
102
+ DropdownButton.Menu = Menu;
103
+ DropdownButton.MenuItem = MenuItem;
104
+ DropdownButton.MenuItemIcon = MenuItemIcon;
105
+ DropdownButton.MenuItemText = MenuItemText;
106
+ DropdownButton.MenuItemTextSubtle = MenuItemTextSubtle;
107
+ DropdownButton.PrimaryAction = PrimaryAction;
108
+ DropdownButton.PrimaryActionText = PrimaryActionText;
109
+ DropdownButton.Trigger = Trigger;
@@ -0,0 +1,177 @@
1
+ /* revert docs-ui resets */
2
+ @layer docs-ui {
3
+ .stldocs-root .stl-ui-dropdown-button {
4
+ all: revert-layer;
5
+
6
+ * {
7
+ all: revert-layer;
8
+ }
9
+ }
10
+ }
11
+
12
+ @layer stl-ui.components {
13
+ .stl-ui-dropdown-button {
14
+ --stl-ui-dropdown-button-color: var(--stl-ui-foreground);
15
+ --stl-ui-dropdown-button-background-color: var(--stl-ui-card-background);
16
+ --stl-ui-dropdown-button-border-color: var(--stl-ui-border);
17
+ --stl-ui-dropdown-button-border-radius: var(--stl-ui-layout-border-radius-sml);
18
+ --stl-ui-dropdown-button-font-size: var(--stl-ui-type-scale-text-sm);
19
+
20
+ --stl-ui-dropdown-button-height: 32px;
21
+ --stl-ui-dropdown-button-padding: 8px 10px;
22
+ --stl-ui-dropdown-button-line-height: 100%;
23
+ --stl-ui-dropdown-button-font-weight: 500;
24
+
25
+ position: relative;
26
+ display: inline-flex;
27
+ align-items: center;
28
+
29
+ background-color: var(--stl-ui-dropdown-button-background-color);
30
+ border: 1px solid var(--stl-ui-dropdown-button-border-color);
31
+ border-radius: var(--stl-ui-dropdown-button-border-radius);
32
+ color: var(--stl-ui-dropdown-button-color);
33
+ gap: 0;
34
+ font-size: var(--stl-ui-dropdown-button-font-size);
35
+
36
+ .stl-ui-dropdown-button__button {
37
+ border: none;
38
+ background: none;
39
+ height: var(--stl-ui-dropdown-button-height);
40
+ padding: var(--stl-ui-dropdown-button-padding);
41
+ line-height: var(--stl-ui-dropdown-button-line-height);
42
+ font-weight: var(--stl-ui-dropdown-button-font-weight);
43
+ cursor: pointer;
44
+ display: flex;
45
+ align-items: center;
46
+ justify-content: center;
47
+
48
+ &:hover {
49
+ background-color: oklch(from var(--stl-ui-foreground) l c h / 0.05);
50
+ border-color: var(--stl-ui-border-emphasis);
51
+ }
52
+ }
53
+
54
+ .stl-ui-dropdown-button--action {
55
+ display: flex;
56
+ align-items: center;
57
+ gap: 8px;
58
+
59
+ &:hover {
60
+ background-color: oklch(from var(--stl-ui-foreground) l c h / 0.05);
61
+ border-color: var(--stl-ui-border-emphasis);
62
+ }
63
+
64
+ &.disabled {
65
+ cursor: not-allowed;
66
+ background-color: oklch(from var(--stl-ui-foreground) l c h / 0.05);
67
+ }
68
+ }
69
+
70
+ .stl-ui-dropdown-button__trigger {
71
+ border-left: 1px solid var(--stl-ui-border);
72
+ border-radius: 0;
73
+
74
+ &:hover {
75
+ background-color: oklch(from var(--stl-ui-foreground) l c h / 0.05);
76
+ border-color: var(--stl-ui-border-emphasis);
77
+ }
78
+ }
79
+
80
+ .stl-ui-dropdown-button__menu {
81
+ --stl-ui-dropdown-button__menu-background-color: var(--stl-ui-card-background);
82
+ --stl-ui-dropdown-button__menu-border-color: var(--stl-ui-border);
83
+ --stl-ui-dropdown-button__menu-box-shadow: var(--stl-ui-shadow-md);
84
+ --stl-ui-dropdown-button__menu-border-radius: var(--stl-ui-layout-border-radius-sml);
85
+
86
+ background-color: var(--stl-ui-dropdown-button__menu-background-color);
87
+ border: 1px solid var(--stl-ui-dropdown-button__menu-border-color);
88
+ box-shadow: var(--stl-ui-dropdown-button__menu-box-shadow);
89
+ border-radius: var(--stl-ui-dropdown-button__menu-border-radius);
90
+
91
+ position: absolute;
92
+ top: 100%;
93
+ right: 0;
94
+ margin-top: 4px;
95
+ z-index: 1000;
96
+ min-width: 100%;
97
+ padding: 4px;
98
+ display: none;
99
+
100
+ &[data-state='open'] {
101
+ display: block;
102
+ }
103
+ }
104
+
105
+ .stl-ui-dropdown-button__menu-item {
106
+ --stl-ui-dropdown-button__menu-item-border-radius: var(--stl-ui-dropdown-button-border-radius);
107
+ --stl-ui-dropdown-button__menu-item-height: var(--stl-ui-dropdown-button-height);
108
+ --stl-ui-dropdown-button__menu-item-line-height: var(--stl-ui-dropdown-button-line-height);
109
+ --stl-ui-dropdown-button__menu-item-hover-background-color: oklch(
110
+ from var(--stl-ui-foreground) l c h / 0.05
111
+ );
112
+
113
+ border-radius: var(--stl-ui-dropdown-button__menu-item-border-radius);
114
+ height: var(--stl-ui-dropdown-button__menu-item-height);
115
+ line-height: var(--stl-ui-dropdown-button__menu-item-line-height);
116
+
117
+ padding: 8px;
118
+ cursor: pointer;
119
+ display: flex;
120
+ align-items: center;
121
+ justify-content: space-between;
122
+ gap: 16px;
123
+
124
+ &:hover {
125
+ background-color: var(--stl-ui-dropdown-button__menu-item-hover-background-color);
126
+ }
127
+
128
+ .stl-ui-dropdown-button__menu-item-content {
129
+ display: flex;
130
+ align-items: center;
131
+ gap: 8px;
132
+ }
133
+
134
+ .stl-ui-dropdown-button__menu-item-text {
135
+ white-space: nowrap;
136
+ }
137
+
138
+ .stl-ui-dropdown-button__menu-item-text--subtle {
139
+ color: var(--stl-ui-foreground-muted);
140
+ }
141
+
142
+ strong {
143
+ color: var(--stl-ui-foreground);
144
+ font-weight: 500;
145
+ }
146
+
147
+ .stl-ui-dropdown-button__menu-item-icon {
148
+ display: flex;
149
+ align-items: center;
150
+ justify-content: center;
151
+ }
152
+
153
+ .stl-ui-dropdown-button__menu-item-external-link-icon {
154
+ --stl-ui-dropdown-button__menu-item-external-link-icon-color: oklch(
155
+ from var(--stl-ui-foreground) l c h / 0.25
156
+ );
157
+
158
+ svg {
159
+ color: var(--stl-ui-dropdown-button__menu-item-external-link-icon-color);
160
+ }
161
+ }
162
+ }
163
+
164
+ hr {
165
+ --stl-ui-dropdown-button__divider-height: 1px;
166
+ --stl-ui-dropdown-button__divider-color: var(--stl-ui-border);
167
+
168
+ height: var(--stl-ui-dropdown-button__divider-height);
169
+ background-color: var(--stl-ui-dropdown-button__divider-color);
170
+ border: none;
171
+
172
+ margin: 4px 0;
173
+ width: calc(100% + 8px);
174
+ transform: translateX(-4px);
175
+ }
176
+ }
177
+ }
package/src/index.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from './components/Button';
2
+ export * from './components/DropdownButton';
2
3
  export * from './components/Callout';
3
4
  export * from './components/DetailsGroup';
@@ -0,0 +1,55 @@
1
+ export function initDropdownButton({
2
+ dropdownId,
3
+ onSelect,
4
+ onPrimaryAction,
5
+ }: {
6
+ dropdownId: string;
7
+ onSelect: (value: string) => void;
8
+ onPrimaryAction: (primaryActionElement: Element) => void;
9
+ }) {
10
+ const dropdown = document.getElementById(dropdownId);
11
+ if (!dropdown) return;
12
+
13
+ const trigger = dropdown.querySelector('[data-part="trigger"]') as HTMLButtonElement | null;
14
+ const menu = dropdown.querySelector('[data-part="menu"]') as HTMLElement | null;
15
+ const primaryAction = dropdown.querySelector('[data-part="primary-action"]');
16
+
17
+ if (!trigger || !menu || !primaryAction) return;
18
+
19
+ let isOpen = false;
20
+
21
+ function toggleDropdown() {
22
+ if (!trigger || !menu) return;
23
+ isOpen = !isOpen;
24
+ menu.dataset.state = isOpen ? 'open' : 'closed';
25
+ trigger.setAttribute('aria-expanded', String(isOpen));
26
+ }
27
+
28
+ trigger.addEventListener('click', toggleDropdown);
29
+
30
+ document.addEventListener('click', (event) => {
31
+ if (!isOpen) return;
32
+ if (!dropdown.contains(event.target as Node)) {
33
+ toggleDropdown();
34
+ }
35
+
36
+ if (primaryAction && primaryAction.contains(event.target as Node)) {
37
+ toggleDropdown();
38
+ }
39
+ });
40
+
41
+ const items = dropdown.querySelectorAll('[data-part="item"]');
42
+ items.forEach((item) => {
43
+ item.addEventListener('click', () => {
44
+ const value = item.getAttribute('data-value');
45
+ if (value) {
46
+ onSelect(value);
47
+ }
48
+ toggleDropdown();
49
+ });
50
+ });
51
+
52
+ primaryAction.addEventListener('click', () => {
53
+ onPrimaryAction(primaryAction);
54
+ });
55
+ }
@@ -0,0 +1 @@
1
+ export * from './dropdown-button';
package/src/styles.css CHANGED
@@ -6,5 +6,6 @@
6
6
  @import './styles/starlight-compat.css';
7
7
 
8
8
  @import './components/button.css';
9
+ @import './components/dropdown-button.css';
9
10
  @import './components/callout.css';
10
11
  @import './components/details.css';