gbs-add-block 2.0.0 → 2.0.2

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.
@@ -0,0 +1,180 @@
1
+ # Styling
2
+
3
+ "Headless" here means the components own behaviour and accessibility and ship a
4
+ default look you can replace at three levels: CSS variables, slot classes, and
5
+ state attributes.
6
+
7
+ ## 1. Stylesheets are per component
8
+
9
+ Each folder has its own `styles.css`. Import the ones you use, once, anywhere:
10
+
11
+ ```ts
12
+ import "component-lib/button/styles.css";
13
+ ```
14
+
15
+ or from a root stylesheet:
16
+
17
+ ```css
18
+ @import "../component-lib/button/styles.css";
19
+ ```
20
+
21
+ Nothing renders correctly without it — the components emit class names only.
22
+
23
+ ## 2. Theme with `--gbs-*` on `:root`
24
+
25
+ One set of variables themes every component at once. This is the whole theming
26
+ API; reach for the other levels only when it is not enough.
27
+
28
+ ```css
29
+ :root {
30
+ --gbs-accent: #7c3aed;
31
+ --gbs-accent-soft: #f3e8ff;
32
+ --gbs-radius: 10px;
33
+ --gbs-font-size: 14px;
34
+ }
35
+ ```
36
+
37
+ Set them on `:root`, not inside a component — components read them through
38
+ inheritance, so anything set on an ancestor reaches every control beneath it.
39
+
40
+ ### Resolution order
41
+
42
+ Each component variable falls through this chain, stopping at the first set:
43
+
44
+ 1. **The component's own variable** — `--in-accent`, `--dg-accent`, `--ck-border`.
45
+ Set this to change one component, or one instance.
46
+ 2. **The shared variable** — `--gbs-accent`. The one you normally set.
47
+ 3. **The DataGrid's variable** — `--dg-accent`, when the grid's stylesheet is
48
+ loaded. Kept for projects that themed the grid before the shared variables existed.
49
+ 4. **The built-in default** — a `light-dark()` pair, so it follows the page's
50
+ colour scheme.
51
+
52
+ ```css
53
+ .in-root { --in-accent: var(--gbs-accent, var(--dg-accent, light-dark(#2563eb, #60a5fa))); }
54
+ ```
55
+
56
+ ### The shared variables
57
+
58
+ Defaults written light / dark.
59
+
60
+ **Surfaces and text:** `--gbs-bg` (`#ffffff`/`#0b0b0e`), `--gbs-fg`
61
+ (`#18181b`/`#f4f4f5`), `--gbs-muted` (`#71717a`/`#a1a1aa`), `--gbs-subtle`
62
+ (`#f4f4f5`/`#1c1c20`), `--gbs-hover` (`#f4f4f5`/`#1f1f23`), `--gbs-input-bg`
63
+ (`#ffffff`/`#121216`), `--gbs-readonly-bg` (`#fafafa`/`#0e0e12`),
64
+ `--gbs-header-bg` (`#fafafa`/`#111114`), `--gbs-header-fg` (`#3f3f46`/`#d4d4d8`).
65
+
66
+ **Borders and shape:** `--gbs-border` (`#e4e4e7`/`#27272a`),
67
+ `--gbs-border-subtle` (`#f0f0f2`/`#1c1c20`), `--gbs-border-control`
68
+ (`#a1a1aa`/`#52525b`), `--gbs-radius` (`8px`), `--gbs-font-size` (`13px`),
69
+ `--gbs-shadow`, `--gbs-backdrop`.
70
+
71
+ **Accent and status:** `--gbs-accent`, `--gbs-accent-soft`,
72
+ `--gbs-accent-strong`, `--gbs-accent-fg`, `--gbs-focus`, `--gbs-danger`,
73
+ `--gbs-danger-fg`, `--gbs-success`, `--gbs-warning`, `--gbs-info`.
74
+
75
+ **Grid-specific:** `--gbs-row-alt`, `--gbs-row-hover`, `--gbs-row-selected`,
76
+ `--gbs-row-selected-hover`, `--gbs-cell-px`, `--gbs-pin-shadow`,
77
+ `--gbs-skeleton`, `--gbs-tab-fg`, `--gbs-tooltip-bg`, `--gbs-tooltip-fg`.
78
+
79
+ ### Per-component prefixes
80
+
81
+ To change one component only, set its own prefix on its root class:
82
+
83
+ | Component | Prefix | Root class |
84
+ | --- | --- | --- |
85
+ | DataGrid | `--dg-*` | `.dg-root` |
86
+ | Combobox | `--cb-*` | `.cb-root` |
87
+ | Toaster | `--ts-*` | `.ts-region` |
88
+ | Input | `--in-*` | `.in-root` |
89
+ | Button | `--bt-*` | `.bt-root` |
90
+
91
+ ```css
92
+ .cb-root { --cb-accent: #7c3aed; --cb-radius: 12px; }
93
+ ```
94
+
95
+ Toasts render on `<body>`, so grid/shared values they inherit must be set on
96
+ `:root`.
97
+
98
+ ## 3. Slot classes
99
+
100
+ `className` goes to the root element only. To reach an inner part, use
101
+ `classNames`, a map of slot name to class string:
102
+
103
+ ```tsx
104
+ <Input label="Email" classNames={{ root: "mb-4", label: "font-semibold", input: "font-mono" }} />
105
+ ```
106
+
107
+ Slots are per component and listed in each `react/props.ts` and in this skill's
108
+ `forms.md` / `overlays.md` / `data-display.md`. Passing a slot that does not
109
+ exist is silently ignored, so check the list.
110
+
111
+ Classes are joined with `cx` from `shared/core/cx.ts`, which drops falsy values
112
+ — a conditional that evaluates to `undefined` contributes nothing.
113
+
114
+ ## 4. Tailwind
115
+
116
+ Every `styles.css` declares:
117
+
118
+ ```css
119
+ @layer theme, base, components, utilities;
120
+ @layer components { /* the component's rules */ }
121
+ ```
122
+
123
+ Component rules live in the `components` layer, so **Tailwind utilities passed
124
+ through `className` / `classNames` win** without `!important`. That is the
125
+ supported way to adjust spacing, typography and layout.
126
+
127
+ ```tsx
128
+ <Button className="w-full sm:w-auto" classNames={{ content: "gap-3" }}>Save</Button>
129
+ ```
130
+
131
+ Do not use `!important`, and do not write selectors against internal class names
132
+ (`.bt-root`, `.dg-cell`) in app CSS — they are implementation detail. Use the
133
+ variables or the slots.
134
+
135
+ ## 5. State attributes
136
+
137
+ Components expose their state as `data-*` attributes, so you can style states
138
+ without tracking them in React.
139
+
140
+ | Attribute | Where |
141
+ | --- | --- |
142
+ | `data-state="open"` / `"closing"` | Combobox, Popover, Menu, Modal, toasts |
143
+ | `data-side` | Popover, Menu, Tooltip — the side it settled on after flipping |
144
+ | `data-size` | Controls that take a `size` |
145
+ | `data-invalid`, `data-disabled` | Form controls |
146
+ | `data-active`, `data-selected` | Combobox options, grid cells and rows |
147
+ | `data-editing`, `data-pinned`, `data-density` | DataGrid |
148
+ | `data-type`, `data-custom`, `data-swiping` | Toasts |
149
+ | `data-position` | Toaster region |
150
+ | `aria-sort` | DataGrid header cells |
151
+
152
+ ```css
153
+ .cb-option[data-active] { outline: 2px solid var(--gbs-focus); }
154
+ ```
155
+
156
+ ## 6. Dark mode
157
+
158
+ Colours are `light-dark()` pairs driven by the page's `color-scheme`, so the
159
+ default is whatever the device prefers. To pin it, set `color-scheme` — the
160
+ components follow:
161
+
162
+ ```css
163
+ :root { color-scheme: light dark; } /* follow the device */
164
+ :root[data-theme="dark"] { color-scheme: dark; }
165
+ :root[data-theme="light"] { color-scheme: light; }
166
+ ```
167
+
168
+ The DataGrid additionally treats a `.dark` or `[data-theme="dark"]` ancestor as
169
+ forcing a scheme.
170
+
171
+ Do not maintain a second palette for dark mode. Override the `--gbs-*` variables
172
+ with `light-dark()` pairs, or set them inside your own `[data-theme="dark"]`
173
+ block, and every component follows.
174
+
175
+ ## 7. Right-to-left
176
+
177
+ The components use logical properties and read `dir` from the document, so RTL
178
+ works without configuration. Arrow keys in Menu, Switch and Tabs mirror
179
+ automatically. The Toaster takes an explicit `dir` prop if one region needs to
180
+ differ from the page.
@@ -0,0 +1,58 @@
1
+ # Toaster and toast
2
+
3
+ Notifications. `toast()` is callable from anywhere — components, event
4
+ handlers, data layers, even outside React. No hook, context or provider.
5
+
6
+ Mount `<Toaster />` **once**; call `toast()` from anywhere — components, event
7
+ handlers, data layers, even outside React. No hook, context or provider.
8
+
9
+ **Import from one path everywhere.** `toast()` and `<Toaster />` meet through a
10
+ shared module-level store; two import paths can create two stores.
11
+
12
+ ```tsx
13
+ // once, near the root
14
+ import { Toaster } from "component-lib/toaster";
15
+ import "component-lib/toaster/styles.css";
16
+ <Toaster />
17
+
18
+ // anywhere
19
+ import { toast } from "component-lib/toaster";
20
+
21
+ toast("Event created", { description: "Monday, 10:00" });
22
+ toast.success("Saved");
23
+ toast.error("Upload failed", { action: { label: "Retry", onClick: retry } });
24
+ toast.warning("Storage almost full");
25
+ toast.info("New version available");
26
+ const id = toast.loading("Uploading…"); // stays until updated
27
+ toast.update(id, { type: "success", title: "Uploaded" });
28
+ toast.dismiss(id); // or toast.dismiss() for all
29
+
30
+ toast.promise(saveUser(data), {
31
+ loading: "Saving…",
32
+ success: (user) => `${user.name} saved`,
33
+ error: (error) => `Could not save: ${(error as Error).message}`,
34
+ });
35
+
36
+ toast.custom(({ dismiss }) => <MyCard onClose={dismiss} />);
37
+ ```
38
+
39
+ Every call returns the toast's id; reusing an on-screen id updates that toast.
40
+
41
+ **Toast options:** `id`, `type` (`default` `success` `error` `warning` `info`
42
+ `loading`), `description`, `duration` (5000; `0`/`Infinity` stays),
43
+ `dismissible`, `action` / `cancel` (`{ label, onClick }`), `icon`, `className`,
44
+ `render`, `onDismiss`, `onAutoClose`.
45
+
46
+ **Toaster props:** `position` (`top-right`), `limit` (3), `duration` (5000),
47
+ `closeButton` (true), `hotkey` (`["altKey","KeyT"]`), `icons`, `store`, `dir`,
48
+ `className`, `classNames`, `style`, `localeText`.
49
+
50
+ Slots: `region`, `list`, `toast`, `icon`, `content`, `title`, `description`,
51
+ `actions`, `action`, `cancel`, `close`.
52
+
53
+ Timers pause while the pointer is over the stack, while focus is inside it, and
54
+ while the tab is hidden. The list is a polite live region; error toasts use
55
+ `role="alert"`. **Alt+T** moves focus to the notifications.
56
+
57
+ `toast()` does nothing during a server render — call it in the browser, e.g.
58
+ after a Server Action resolves.
package/README.md CHANGED
@@ -1,19 +1,42 @@
1
- # GBS Building Blocks 2.0 (v2.0.0)
2
-
3
- Latest and upgraded version of GBS building blocks with headless UI and removed dependencies.
4
-
5
- ## Documentation
6
-
7
- For detailed documentation on usage and props, Please visit: [Building Block Documentation](https://gramprokit.vercel.app)
8
-
9
- ## Beta Components
10
-
11
- New 2.0.0 beta (current version) is available for testing and feedback, Please visit: [Building Block Documentation v2.0.0 beta](https://gramprokit.vercel.app)
12
-
13
- ## What's New 🎉 (Ver 2.0.0)
14
-
15
- - Update Candidate for next major change 2.0.0
16
-
17
- ## Authors
18
-
19
- - [@anandhuremanan](https://www.github.com/anandhuremanan)
1
+ # GBS Building Blocks 2.0 (v2.0.2)
2
+
3
+ Latest and upgraded version of GBS building blocks with headless UI and removed dependencies.
4
+
5
+ ## Documentation
6
+
7
+ For detailed documentation on usage and props, Please visit: [Building Block Documentation](https://gramprokit.vercel.app)
8
+
9
+ ## Beta Components
10
+
11
+ New 2.0.0 beta (current version) is available for testing and feedback, Please visit: [Building Block Documentation v2.0.0 beta](https://gramprokit.vercel.app)
12
+
13
+ ## Agent skill
14
+
15
+ Install the skill once per project so a coding agent uses these components
16
+ correctly instead of guessing at the API:
17
+
18
+ ```bash
19
+ npx gbs-add-block@latest -skill
20
+ ```
21
+
22
+ It writes the skill at the root of the project you run it in, in the place each
23
+ agent looks:
24
+
25
+ | Agent | Gets |
26
+ | --- | --- |
27
+ | GBS SE Agent | `.gbs/skills/gbs-components/` (canonical) |
28
+ | Claude Code | `.claude/skills/gbs-components/` |
29
+ | Antigravity | `.agents/rules/gbs-components.md` |
30
+ | Codex | a marked block in `AGENTS.md` |
31
+
32
+ Pick a subset with `--for claude,codex`, or `--for none` for just `.gbs/`.
33
+ Commit the result so everyone's agent picks it up. Re-run to update; a file you
34
+ have edited is never replaced without `--force`.
35
+
36
+ ## What's New 🎉 (Ver 2.0.2)
37
+
38
+ - Update Candidate for next major change 2.0.0
39
+
40
+ ## Authors
41
+
42
+ - [@anandhuremanan](https://www.github.com/anandhuremanan)