@thebase/ui 1.1.5 → 1.1.7

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.
@@ -477,6 +477,19 @@
477
477
  ],
478
478
  "templateName": "baseui.ClipboardButton"
479
479
  },
480
+ {
481
+ "name": "code-editor",
482
+ "type": "owl",
483
+ "dependencies": [
484
+ "owl"
485
+ ],
486
+ "attributes": [],
487
+ "events": [],
488
+ "owlComponents": [
489
+ "CodeEditor"
490
+ ],
491
+ "templateName": "baseui.CodeEditor"
492
+ },
480
493
  {
481
494
  "name": "collapsible",
482
495
  "type": "owl",
@@ -870,30 +883,6 @@
870
883
  ],
871
884
  "templateName": "baseui.Input"
872
885
  },
873
- {
874
- "name": "input-group",
875
- "type": "static",
876
- "dependencies": [],
877
- "attributes": [
878
- "b-ui",
879
- "b-input-group-addon",
880
- "b-input-group-button",
881
- "b-input-group-text",
882
- "b-att-align",
883
- "b-att-size",
884
- "b-att-variant"
885
- ],
886
- "events": [],
887
- "owlComponents": [
888
- "InputGroup",
889
- "InputGroupAddon",
890
- "InputGroupButton",
891
- "InputGroupText",
892
- "InputGroupInput",
893
- "InputGroupTextarea"
894
- ],
895
- "templateName": "baseui.InputGroup"
896
- },
897
886
  {
898
887
  "name": "input-otp",
899
888
  "type": "owl",
@@ -1697,13 +1686,13 @@
1697
1686
  }
1698
1687
  ],
1699
1688
  "integrity": {
1700
- "baseui.min.css": "sha384-MzYm4tnpt85MomNRXCdL9Rs4jDdw2qAPIoagZbC8/1kQLnPbHlW2tIf2F9OmRgPj",
1689
+ "baseui.min.css": "sha384-Nx35SpSUwT8KeoaINtj0FdbfinuODJWHtYQbAaGAuFL4+Q8i0IIa5WcXnqhfQP02",
1701
1690
  "bootstrap.bundle.min.js": "sha384-RMbllTJcplkCRnELNTOc5Kz/3AvFDE/rNlJqWqfgmRWruobClBdfwvl10akQZkR1",
1702
- "baseui.min.js": "sha384-GcCWnFI6t+f/dc757+Crav6N80AmqwuB2K8kSTaeb08ErsYd9mTHA1aKB/rnQltB",
1703
- "baseui.esm.js": "sha384-UBVYm8E0mq0ZAVhefx5fmnAJVT31BD4cukBRhCyGIqxJ8AtoRNqg92NJ6uC233zU",
1691
+ "baseui.min.js": "sha384-/ePf9SGI23sWot17uRZoqXrAHOujul5BK4caZoxuAQBdZBLAHEwgsa6LaWFjeF9T",
1692
+ "baseui.esm.js": "sha384-DnOUezGZVb68/7F/evjpTPUwAe/l1cOKZsOf1wHDQ3vrZsmowB4AUH2IOxW7/3Mr",
1704
1693
  "baseui.icons.esm.js": "sha384-hj39VMhzcFvmYnjob2hlioMOAqwAXCURGreF6s9RitXFp/iYi7rUdqtfCI+ICQeS",
1705
- "baseui.templates.xml": "sha384-9llWP0L4BuRpij3wEYymvwY8MOBd11X9mdXqI2JtYHr9j2tCrTbE0hIEMNCDOFdj",
1706
- "baseui.block-viewer.esm.js": "sha384-5Y2lUNdq6p3i8srVH4rVWtYLO7mFPP6Pqn80e4Ih32c/PgQqy1HDf6nI04mu6yLa",
1694
+ "baseui.templates.xml": "sha384-fWKcLP/7ZpBknt3jRvt/BzQk4o/xesmniCK72dwLtafqoG8yubhs6iMqdeweHeUk",
1695
+ "baseui.block-viewer.esm.js": "sha384-8uPD/d2PWi0hAlIxP0qmYsQBZFlcjmnyFmaBItLryEgqm4XwEdwxABAnFngmBzFx",
1707
1696
  "baseui.analytics.esm.js": "sha384-M6TVmchmceTvpSzgI+DNA6zAn9xmz9a+YEexCLslSo/Ngxyp2kmzs9fm+PxWy+Da",
1708
1697
  "baseui.analytics.min.js": "sha384-B0hBkVDbT7gmDmUMazlN4Nc1KnYGSpL+IcW2hd8840knx73HGImPgGs84MvS3hKE",
1709
1698
  "icons/lucide.json": "sha384-mc5mzpmq9eOgZVa2IcjrL33Ty4nMXE8aoZMfy+lgkC/jMQ4aYnk2S58mFsSGFnW1",
@@ -1059,6 +1059,48 @@
1059
1059
  </Button>
1060
1060
  </t>
1061
1061
  <t t-name="ClipboardButton" t-call="baseui.ClipboardButton"/>
1062
+ <t t-name="baseui.CodeEditor">
1063
+ <section t-att-class="classNames" t-att-style="props.style">
1064
+ <div class="bu-code-editor-header">
1065
+ <div class="bu-code-editor-heading">
1066
+ <h3 t-if="props.title" class="h6 fw-semibold mb-0" t-esc="props.title"/>
1067
+ <small t-if="globals.length or props.hint" class="text-body-secondary">
1068
+ <t t-if="globals.length">Globals: <t t-foreach="globals" t-as="name" t-key="name"><code t-esc="name"/><t t-if="!name_last">, </t></t>. </t>
1069
+ <t t-esc="props.hint"/>
1070
+ </small>
1071
+ </div>
1072
+ <div class="bu-code-editor-actions">
1073
+ <Spinner t-if="state.loading" className="'spinner-border-sm'" label="'Loading'"/>
1074
+ <Badge variant="'muted'" label="language.label"/>
1075
+ <Badge variant="'secondary'" label="lineLabel"/>
1076
+ <t t-if="props.upload">
1077
+ <input type="file" class="d-none" t-ref="fileInput" t-on-change="onFileChange"/>
1078
+ <Button variant="'outline'" size="'sm'" icon="'upload'" label="'Open file'" onClick="() => this.openPicker()"/>
1079
+ </t>
1080
+ <Button t-if="showFormat" variant="'outline'" size="'sm'" icon="'wand-sparkles'" label="'Format'" disabled="!code" onClick="() => this.format()"/>
1081
+ <ClipboardButton variant="'outline'" size="'sm'" value="code" label="'Copy'" copiedLabel="'Copied'" disabled="!code"/>
1082
+ <Button t-if="showToggle" variant="'outline'" size="'sm'" icon="isReadonly ? 'pencil' : 'eye'" label="isReadonly ? 'Edit' : 'View'" onClick="() => this.toggleEditing()"/>
1083
+ </div>
1084
+ </div>
1085
+ <Alert t-if="state.error" variant="'destructive'"><AlertDescription t-esc="state.error"/></Alert>
1086
+
1087
+ <!-- One scroll container for gutter + code: the transparent textarea is stretched over the colouring pre, so both scroll together and no scroll-sync code is needed. -->
1088
+ <div class="bu-code-editor-box" t-att-class="{ 'is-readonly': isReadonly }">
1089
+ <pre aria-hidden="true" class="bu-code-editor-text bu-code-editor-gutter" t-esc="lineNumbers"/>
1090
+ <div class="bu-code-editor-body">
1091
+ <pre aria-hidden="true" class="bu-code-editor-text"><t t-foreach="tokens" t-as="tok" t-key="tok_index"><span t-att-class="tok.className" t-esc="tok.text"/></t></pre>
1092
+ <textarea t-if="!isReadonly" class="bu-code-editor-text bu-code-editor-input"
1093
+ wrap="off" spellcheck="false" autocapitalize="off" autocomplete="off" autocorrect="off"
1094
+ t-ref="input" t-att-id="props.id" t-att-aria-label="ariaLabel"
1095
+ t-on-input="onInput" t-on-keydown="onKeydown" t-on-click="(ev) => this.revealCaret(ev.target)"/>
1096
+ </div>
1097
+ </div>
1098
+ <small t-if="!isReadonly" class="text-body-secondary">
1099
+ <Kbd>Tab</Kbd> indents, <Kbd>Shift</Kbd>+<Kbd>Tab</Kbd> outdents, <Kbd>Esc</Kbd> then <Kbd>Tab</Kbd> leaves the editor.
1100
+ </small>
1101
+ </section>
1102
+ </t>
1103
+ <t t-name="CodeEditor" t-call="baseui.CodeEditor"/>
1062
1104
  <t t-name="baseui.collapsible">
1063
1105
  <div b-ui="collapsible"><t t-slot="default"/></div>
1064
1106
  </t>
@@ -1766,13 +1808,22 @@
1766
1808
  ></span>
1767
1809
  </t>
1768
1810
  <t t-name="Icon" t-call="baseui.Icon"/>
1769
- <t t-name="baseui.Outlined">
1811
+ <t t-name="baseui.Outlined.label">
1812
+ <div t-if="label" class="bu-input-label">
1813
+ <span class="bu-input-label-text" t-esc="label"/>
1814
+ <Tooltip t-if="tipText" content="tipText" className="'bu-input-tip'"><t t-set-slot="trigger"><IconCircleQuestionMark/></t></Tooltip>
1815
+ </div>
1816
+ </t>
1817
+ <t t-name="baseui.Outlined">
1770
1818
  <div t-if="isOutlined" t-att-class="outlinedClassNames" t-att-style="labelStyle">
1771
- <div class="bu-input-box">
1819
+ <div class="bu-input-box" t-ref="box">
1772
1820
  <Icon t-if="leadingIcon" name="leadingIcon" className="'bu-input-icon bu-input-leading'"/>
1773
1821
  <t t-out="0"/>
1774
- <span class="bu-input-label" t-esc="label"/>
1822
+ <t t-call="baseui.Outlined.label"/>
1775
1823
  <Icon t-if="trailingIcon" name="trailingIcon" className="'bu-input-icon bu-input-trailing'"/>
1824
+ <div t-if="hasStart" class="bu-input-slot bu-input-slot-start" t-ref="start"><t t-slot="start"/></div>
1825
+ <div t-if="hasEnd" class="bu-input-slot bu-input-slot-end" t-ref="end"><t t-slot="end"/></div>
1826
+ <div t-if="hasFooter" class="bu-input-slot bu-input-slot-footer" t-ref="footer"><t t-slot="footer"/></div>
1776
1827
  </div>
1777
1828
  <div t-if="supportingText or props.maxLength" class="bu-input-support">
1778
1829
  <span t-att-id="supportId" t-esc="supportingText"/>
@@ -1808,78 +1859,6 @@
1808
1859
  />
1809
1860
  </t>
1810
1861
  <t t-name="Input" t-call="baseui.Input"/>
1811
- <t t-name="baseui.input-group"><div b-ui="input-group"><t t-esc="props.content"/></div></t>
1812
- <t t-name="baseui.InputGroup">
1813
- <t t-call="baseui.Outlined"><t t-call="baseui.InputGroup.box"/></t>
1814
- </t>
1815
- <t t-name="baseui.InputGroup.box">
1816
- <div t-att-class="classNames" t-att-style="props.style" data-slot="input-group" role="group"
1817
- t-att-aria-describedby="describedBy"><t t-slot="default"/></div>
1818
- </t>
1819
- <t t-name="baseui.InputGroupAddon">
1820
- <div
1821
- t-att-class="classNames"
1822
- t-att-style="props.style"
1823
- t-att-data-align="align"
1824
- data-slot="input-group-addon"
1825
- role="group"
1826
- t-on-click="onClick"
1827
- ><t t-slot="default"/></div>
1828
- </t>
1829
- <t t-name="baseui.InputGroupButton">
1830
- <Button
1831
- unstyled="true"
1832
- className="classNames"
1833
- style="props.style"
1834
- type="props.type"
1835
- disabled="props.disabled"
1836
- label="props.label"
1837
- attrs="buttonAttrs"
1838
- onClick="(event) => this.onClick(event)"
1839
- ><t t-slot="default"/></Button>
1840
- </t>
1841
- <t t-name="baseui.InputGroupText">
1842
- <span t-att-class="classNames" t-att-style="props.style" data-slot="input-group-text"><t t-slot="default"/></span>
1843
- </t>
1844
- <t t-name="baseui.InputGroupInput">
1845
- <input
1846
- t-att-id="props.id"
1847
- t-att-name="props.name"
1848
- t-att-autocomplete="props.autocomplete"
1849
- t-att-class="classNames"
1850
- t-att-style="props.style"
1851
- t-att-type="props.type || 'text'"
1852
- t-att-placeholder="fieldPlaceholder"
1853
- t-att-value="props.value"
1854
- t-att-disabled="props.disabled"
1855
- t-att-readonly="props.readonly"
1856
- t-att-aria-invalid="props.invalid ? 'true' : undefined"
1857
- data-slot="input-group-control"
1858
- t-on-input="onInput"
1859
- t-on-change="onChange"
1860
- />
1861
- </t>
1862
- <t t-name="baseui.InputGroupTextarea">
1863
- <textarea
1864
- t-att-class="classNames"
1865
- t-att-style="props.style"
1866
- t-att-placeholder="fieldPlaceholder"
1867
- t-att-rows="props.rows"
1868
- t-att-disabled="props.disabled"
1869
- t-att-readonly="props.readonly"
1870
- t-att-value="props.value"
1871
- t-att-aria-invalid="props.invalid ? 'true' : undefined"
1872
- data-slot="input-group-control"
1873
- t-on-input="onInput"
1874
- t-on-change="onChange"
1875
- ></textarea>
1876
- </t>
1877
- <t t-name="InputGroup" t-call="baseui.InputGroup"/>
1878
- <t t-name="InputGroupAddon" t-call="baseui.InputGroupAddon"/>
1879
- <t t-name="InputGroupButton" t-call="baseui.InputGroupButton"/>
1880
- <t t-name="InputGroupText" t-call="baseui.InputGroupText"/>
1881
- <t t-name="InputGroupInput" t-call="baseui.InputGroupInput"/>
1882
- <t t-name="InputGroupTextarea" t-call="baseui.InputGroupTextarea"/>
1883
1862
  <t t-name="baseui.input-otp">
1884
1863
  <div class="bu-input-otp"/>
1885
1864
  </t>
@@ -2275,7 +2254,7 @@
2275
2254
  <t t-name="baseui.Select">
2276
2255
  <div t-att-class="classNames" t-att-style="rootStyle" t-ref="root">
2277
2256
  <t t-slot="default"/>
2278
- <span t-if="isOutlined" class="bu-input-label" t-esc="label"/>
2257
+ <t t-if="isOutlined" t-call="baseui.Outlined.label"/>
2279
2258
  <div t-if="isOutlined and supportingText" class="bu-input-support">
2280
2259
  <span t-att-id="supportId" t-esc="supportingText"/>
2281
2260
  </div>
@@ -2705,7 +2684,13 @@
2705
2684
  t-att-disabled="props.disabled"
2706
2685
  t-on-change="onChange"
2707
2686
  />
2708
- <t t-slot="default"/>
2687
+ <span class="bu-switch-label">
2688
+ <t t-slot="default"/>
2689
+ <span t-if="tipText" class="bu-switch-tip" t-on-click.prevent.stop="">
2690
+ <Tooltip content="tipText" className="'bu-input-tip'"><t t-set-slot="trigger"><IconCircleQuestionMark/></t></Tooltip>
2691
+ </span>
2692
+ </span>
2693
+ <small t-if="supportingText" class="bu-switch-support" t-esc="supportingText"/>
2709
2694
  </label>
2710
2695
  </t>
2711
2696
  <t t-name="Switch" t-call="baseui.Switch"/>
package/docs/analytics.md CHANGED
@@ -13,12 +13,12 @@ init({ backendUrl: "https://stats.example.com" });
13
13
  ```html
14
14
  <!-- ES module from the CDN (or map it as "@base/analytics" in an import map) -->
15
15
  <script type="module">
16
- import { init } from "https://cdn.jsdelivr.net/npm/@thebase/ui@1.1.5/dist/baseui.analytics.esm.js";
16
+ import { init } from "https://cdn.jsdelivr.net/npm/@thebase/ui@1.1.7/dist/baseui.analytics.esm.js";
17
17
  init({ backendUrl: "https://stats.example.com" });
18
18
  </script>
19
19
 
20
20
  <!-- Classic script tag: sets window.thebase.analytics (load order vs dist/baseui.min.js doesn't matter) -->
21
- <script src="https://cdn.jsdelivr.net/npm/@thebase/ui@1.1.5/dist/baseui.analytics.min.js"></script>
21
+ <script src="https://cdn.jsdelivr.net/npm/@thebase/ui@1.1.7/dist/baseui.analytics.min.js"></script>
22
22
  <script>
23
23
  thebase.analytics.init({ backendUrl: "https://stats.example.com" });
24
24
  </script>
@@ -228,7 +228,7 @@ curl -i -X POST http://localhost:8080/api/event -H 'Content-Type: text/plain' \
228
228
 
229
229
  [`examples/analytics/`](../examples/analytics/dashboard/?backend=http://localhost:8080) contains a working dashboard plus two complete sample backends: [`server-go`](../examples/analytics/server-go/main.go) (Fiber v3) and [`server-fastapi`](../examples/analytics/server-fastapi/main.py). Each one extends the receivers above with an in-memory store, a daily-salted cookieless visitor hash, a `GET /api/stats` endpoint, and static hosting for the dashboard.
230
230
 
231
- The dashboard ([`dashboard/`](../examples/analytics/dashboard/?backend=http://localhost:8080)) is a pure application that loads `@thebase/ui@1.1.5` from jsDelivr: KPI `Card`s, an area `Chart`, top pages/sources/events `Table`s, site and period `NativeSelect`s, and a `ThemeButton`. It refreshes every 30 s and tracks its own visits through `@thebase/ui/analytics`, so a fresh backend has data straight away.
231
+ The dashboard ([`dashboard/`](../examples/analytics/dashboard/?backend=http://localhost:8080)) is a pure application that loads `@thebase/ui@1.1.7` from jsDelivr: KPI `Card`s, an area `Chart`, top pages/sources/events `Table`s, site and period `NativeSelect`s, and a `ThemeButton`. It refreshes every 30 s and tracks its own visits through `@thebase/ui/analytics`, so a fresh backend has data straight away.
232
232
 
233
233
  ```sh
234
234
  # Go (1.25+)
package/docs/blocks.md CHANGED
@@ -13,7 +13,7 @@ Blocks are not standalone runtime components. Paste the markup and load the norm
13
13
  <script src="https://cdn.jsdelivr.net/npm/@thebase/ui@latest/dist/baseui.min.js" defer></script>
14
14
  ```
15
15
 
16
- `https://unpkg.com/@thebase/ui@latest/dist/...` mirrors the same files as an alternative CDN if jsDelivr is unreachable. Pin an exact version (e.g. `@1.1.5`, or `@1` to take only non-breaking updates) instead of `@latest` for production. Blocks are static markup, so they only need the static `b-ui` runtime above — see [Usage Guide](usage-guide.md) if the surrounding page is itself an application and you'd rather compose the equivalent layout from [Base Components](owl-components.md).
16
+ `https://unpkg.com/@thebase/ui@latest/dist/...` mirrors the same files as an alternative CDN if jsDelivr is unreachable. Pin an exact version (e.g. `@1.1.7`, or `@1` to take only non-breaking updates) instead of `@latest` for production. Blocks are static markup, so they only need the static `b-ui` runtime above — see [Usage Guide](usage-guide.md) if the surrounding page is itself an application and you'd rather compose the equivalent layout from [Base Components](owl-components.md).
17
17
 
18
18
  Use `b-block` to select the block style:
19
19
 
@@ -112,6 +112,8 @@ Interactive components emit documented `baseui:*` events from their root element
112
112
 
113
113
  The component inherits the Base UI semantic tokens plus shadcn-compatible chart tokens: `--b-chart-1` through `--b-chart-5`. Area-card examples also use `--b-chart-height`, `--b-chart-grid`, `b-chart-area`, `b-chart-line`, `b-chart-axis`, `b-chart-footer`, `b-chart-trend`, and `b-chart-range`.
114
114
 
115
+ The plot (`b-chart-plot`) has a fixed height of `--b-chart-height` (default `var(--b50)`), and each `b-att-value` column draws its bar from the bottom as a percentage of the largest value in the chart. Override `--b-chart-height` on the chart element to make it taller or shorter; the bar height needs this definite plot height to resolve.
116
+
115
117
  ## Accessibility behavior
116
118
 
117
119
  The component preserves authored semantic HTML and adds ARIA roles or state attributes where enhancement is required.
@@ -0,0 +1,77 @@
1
+ # Code Editor
2
+
3
+ A dependency-free code box with line numbers, syntax colouring, Tab/Shift+Tab indent, Enter auto-indent and Format, Copy and Edit/View buttons. Pure Base only: it has no static `b-ui` adapter. Name the language with `codeLang`. Editable by default: pass `onChange` to own the text, or omit it and the editor keeps its own edits; add `readonly` to start in reading mode. The **Edit** button (right of Copy) toggles between reading (no typing, no Format button) and editing (**View** switches back).
4
+
5
+ ## Base component
6
+
7
+ ```js
8
+ import { CodeEditor } from "@thebase/ui";
9
+ ```
10
+
11
+ ```base-ui
12
+ <div class="d-flex flex-column gap-3 w-100">
13
+ <CodeEditor title="'main.go'" codeLang="'go'" value="'package main\n\nimport \'fmt\'\n\n// Greets the world.\nfunc main() {\n\tfmt.Println(\'hello\', 42)\n}'"/>
14
+ <CodeEditor codeLang="'sql'" value="'SELECT id, name\nFROM users\nWHERE active = true -- only live accounts\nLIMIT 10;'"/>
15
+ </div>
16
+ ```
17
+
18
+ Editable, with state:
19
+
20
+ ```js
21
+ this.state = useState({ code: "int main(void) {\n return 0;\n}" });
22
+ ```
23
+
24
+ ```xml
25
+ <CodeEditor codeLang="'c'" value="state.code" onChange="(code) => state.code = code"/>
26
+ ```
27
+
28
+ | Prop | Type | Default |
29
+ | --- | --- | --- |
30
+ | `codeLang` | `String` | picked from the loaded file's extension, else `"plaintext"`; language to colour (see below), case-insensitive; unknown names fall back to plain text |
31
+ | `value` | `String` | the code; the component never mutates it |
32
+ | `src` | `String` | URL of a code file to fetch and show; reloads when it changes. Replaces `value` once loaded. Cross-origin URLs need CORS |
33
+ | `upload` | `Boolean` | shows an "Open file" button that loads a local file into the editor |
34
+ | `onLoad` | `Function` | `({ code, name }) => void`, after a file loads from `src` or an upload |
35
+ | `onError` | `Function` | `(error) => void`, when `src` or an upload cannot be read (an error alert is also shown) |
36
+ | `format` | `Boolean` | shows the **Format** button while editable (default on); `false` hides it |
37
+ | `toggle` | `Boolean` | shows the Edit/View button (default on); `false` locks the mode set by `readonly` |
38
+ | `onChange` | `Function` | `(code) => void`, called on every edit; omit it and the editor keeps its own edits |
39
+ | `readonly` | `Boolean` | starts in reading mode; users can switch with the Edit button unless `toggle` is `false` |
40
+ | `title` | `String` | heading, also the textarea's `aria-label`; defaults to `"<Language> code"` |
41
+ | `globals` | `Array<String>` | names your runtime binds; listed in the hint and coloured as builtins |
42
+ | `hint` | `String` | free-text help shown after the globals |
43
+ | `id` | `String` | textarea id, so an external `<label for>` can target the editor |
44
+ | `className` / `style` | `String` / `String \| Object` | on the root |
45
+
46
+ ## Formatting
47
+
48
+ The **Format** button (or `Shift+Alt+F` in the editor) re-indents the code for the current `codeLang`, then reports it through `onChange`. It is a dependency-free re-indenter, not a full pretty-printer: it never re-wraps or rewrites code.
49
+
50
+ | Languages | What Format does |
51
+ | --- | --- |
52
+ | `json` | parses and pretty-prints with 2 spaces; invalid JSON shows an error alert, calls `onError` and leaves the text unchanged |
53
+ | `javascript`, `typescript`, `go`, `c`, `cpp`, `java`, `csharp`, `kotlin`, `swift`, `rust`, `php`, `css` | re-indents by bracket depth with the language's indent (tab for Go); brackets inside strings and comments are ignored, lines inside multi-line strings/comments are untouched, C/C++ `#` lines stay at the left margin |
54
+ | `html`, `xml` | re-indents by tag depth (void HTML tags like `<br>` and `/>` self-closing tags don't nest; tags inside comments and attribute values are ignored) |
55
+ | `lua` | re-indents by `function/if/for/while/repeat … end/until` blocks and brackets |
56
+ | everything else (`python`, `yaml`, `ruby`, `bash`, `sql`, plain text) | only trims trailing spaces; indentation is left alone because it carries meaning or has no safe rule |
57
+
58
+ All languages also collapse runs of blank lines to one and end the text with a single newline.
59
+
60
+ ## Loading files
61
+
62
+ ```xml
63
+ <CodeEditor src="'/examples/main.go'"/>
64
+ <CodeEditor upload="true" title="'Open a file to view it'"/>
65
+ ```
66
+
67
+ `src` fetches the URL as text and shows it; the language comes from `codeLang`, or from the file extension (`.go`, `.c`, `.java`, `.mjs`, …) when `codeLang` is not set. `upload` adds an **Open file** button that reads a local file in the browser (nothing is uploaded anywhere). A loaded file replaces `value`; edits to it stay in the editor and are still reported through `onChange`. A failed fetch (HTTP error, network or CORS) shows an error alert and calls `onError`.
68
+
69
+ ## Languages
70
+
71
+ `javascript` (`js`, `jsx`), `typescript` (`ts`, `tsx`), `go` (`golang`), `c` (`h`), `cpp` (`c++`, `cc`, `hpp`), `java`, `csharp` (`cs`, `c#`), `kotlin` (`kt`), `swift`, `rust` (`rs`), `php`, `python` (`py`), `ruby` (`rb`), `bash` (`sh`, `shell`), `sql` (`postgres`, `mysql`), `json`, `yaml` (`yml`), `css`, `html` (`htm`), `xml` (`svg`), `lua`, `plaintext`.
72
+
73
+ Colouring is display-only and follows `codeLang`: comments, strings, numbers, keywords, builtins, function calls (a word followed by `(`), types (`Capitalized` names), HTML/XML tags, attribute names and `&entities;`, `key:` names in JSON/YAML, CSS properties and `#hex` colours, `@Annotations` (Java, Kotlin, TypeScript, Python) and `$variables` (PHP, shell). Colours come from `--bu-code-*` CSS variables on `.bu-code-editor` (light and dark presets built in), so a theme can override them; nothing is parsed or validated. The Tab key inserts one indent for the language (a tab for Go, 4 spaces for C/Java/Python/Rust/…, 2 for the rest). `Esc` then `Tab` leaves the editor for keyboard users.
74
+
75
+ Live demo: the `code-editor-demo` block in the Blocks gallery (`examples/blocks/code-editor-demo.html`, Go/C/Java/JavaScript/HTML/XML/JSON/CSS/SQL tabs plus file loading).
76
+
77
+ The chrome is built from [Badge](badge.md), [ClipboardButton](clipboard-button.md) and [Kbd](kbd.md).
@@ -24,6 +24,16 @@ import { Combobox } from "@thebase/ui";
24
24
  </div>
25
25
  ```
26
26
 
27
+ ### Help tooltip (`useTip`)
28
+
29
+ Set `useTip="1"` to move `supportingText` into a tooltip: a question-mark icon appears right after the label, in the same label box, and the text shows on hover or focus. Error text still shows under the field.
30
+
31
+ ```base-ui
32
+ <div style="max-width: 28rem" class="w-100 pt-3">
33
+ <Combobox options="[{ value: 'nextjs', label: 'Next.js' }, { value: 'remix', label: 'Remix' }]" label="'Framework'" supportingText="'Pick the one you use most'" useTip="1"/>
34
+ </div>
35
+ ```
36
+
27
37
  | Component | Prop | Type | Notes |
28
38
  | --- | --- | --- | --- |
29
39
  | `Combobox` | `options` | `Array` | required |
@@ -32,7 +42,7 @@ import { Combobox } from "@thebase/ui";
32
42
  | `Combobox` | `className` | `String` | optional |
33
43
  | `Combobox` | `id` | `String` | optional, e.g. for `Label`'s `for` |
34
44
  | `Combobox` | `onChange` | `Function` | optional |
35
- | `Combobox` | `label`, `labelBackground`, `supportingText`, `errorText`, `invalid`, `disabled` | `String` / `Boolean` | Material-style outlined field, same behaviour as [Input](/examples/blocks.html#/docs/components/input): the label floats onto the border, `errorText` replaces `supportingText`. Also inherited from a parent `Field`. |
45
+ | `Combobox` | `label`, `labelBackground`, `supportingText`, `useTip`, `errorText`, `invalid`, `disabled` | `String` / `Boolean` | Material-style outlined field, same behaviour as [Input](/examples/blocks.html#/docs/components/input): the label floats onto the border, `errorText` replaces `supportingText`. Also inherited from a parent `Field`. |
36
46
 
37
47
  See [Base Components](/examples/blocks.html#/docs/guide/owl-components) for how to load `@base/owl` and `dist/baseui.templates.xml`.
38
48
 
@@ -19,13 +19,23 @@ import { DatePicker } from "@thebase/ui";
19
19
  </div>
20
20
  ```
21
21
 
22
+ ### Help tooltip (`useTip`)
23
+
24
+ Set `useTip="1"` to move `supportingText` into a tooltip: a question-mark icon appears right after the label, in the same label box, and the text shows on hover or focus. Error text still shows under the field.
25
+
26
+ ```base-ui
27
+ <div style="max-width: 28rem" class="w-100 pt-3">
28
+ <DatePicker label="'Date of birth'" supportingText="'As on your ID'" useTip="1"/>
29
+ </div>
30
+ ```
31
+
22
32
  | Component | Prop | Type | Notes |
23
33
  | --- | --- | --- | --- |
24
34
  | `DatePicker` | `value` | `String` | optional |
25
35
  | `DatePicker` | `disabled` | `Boolean` | optional |
26
36
  | `DatePicker` | `className` | `String` | optional |
27
37
  | `DatePicker` | `onChange` | `Function` | optional |
28
- | `DatePicker` | `label`, `labelBackground`, `supportingText`, `errorText`, `invalid` | `String` / `Boolean` | Material-style outlined field, same behaviour as [Input](/examples/blocks.html#/docs/components/input): the label floats onto the border, `errorText` replaces `supportingText`. Also inherited from a parent `Field`. |
38
+ | `DatePicker` | `label`, `labelBackground`, `supportingText`, `useTip`, `errorText`, `invalid` | `String` / `Boolean` | Material-style outlined field, same behaviour as [Input](/examples/blocks.html#/docs/components/input): the label floats onto the border, `errorText` replaces `supportingText`. Also inherited from a parent `Field`. |
29
39
 
30
40
  See [Base Components](/examples/blocks.html#/docs/guide/owl-components) for how to load `@base/owl` and `dist/baseui.templates.xml`.
31
41
 
@@ -63,4 +63,4 @@ See [Base Components](/examples/blocks.html#/docs/guide/owl-components) for how
63
63
  </div>
64
64
  ```
65
65
 
66
- The Base UI sets `role="status"` by default. Use `b-att-variant="outline"` for a dashed container and `b-att-variant="background"` for a muted panel; avatar, avatar-group, input-group, and RTL states are composed by placing those components inside `b-empty-media` or `b-empty-content`.
66
+ The Base UI sets `role="status"` by default. Use `b-att-variant="outline"` for a dashed container and `b-att-variant="background"` for a muted panel; avatar, avatar-group, and RTL states are composed by placing those components inside `b-empty-media` or `b-empty-content`.
@@ -81,7 +81,7 @@ import {
81
81
 
82
82
  ### Outlined controls
83
83
 
84
- `Field` accepts `label`, `labelBackground`, `description`, `error` and `invalid`, and hands them to the control inside it. `Input`, `Textarea`, `NativeSelect`, `Select`, `Combobox` and `DatePicker` draw them in the Material outlined style (floating label, helper text, error text and icon). A control's own `label`/`supportingText`/`errorText` props win over the `Field` values.
84
+ `Field` accepts `label`, `labelBackground`, `description`, `useTip` (1 = show the description in a tooltip), `error` and `invalid`, and hands them to the control inside it. `Input`, `Textarea`, `NativeSelect`, `Select`, `Combobox` and `DatePicker` draw them in the Material outlined style (floating label, helper text, error text and icon). A control's own `label`/`supportingText`/`errorText` props win over the `Field` values.
85
85
 
86
86
  ```base-ui
87
87
  <div class="d-grid gap-4" style="max-width: 28rem; width: 100%">
@@ -90,6 +90,14 @@ import {
90
90
  </div>
91
91
  ```
92
92
 
93
+ ```base-ui
94
+ <div style="max-width: 28rem; width: 100%">
95
+ <Field label="'Email'" description="'We never share it'" useTip="1"><Input leadingIcon="'mail'"/></Field>
96
+ </div>
97
+ ```
98
+
99
+ With `useTip="1"` on `Field`, the description moves into a tooltip on a question-mark icon right after the label, as above.
100
+
93
101
  Use one control per labelled `Field`. For checkboxes, radios and switches keep `FieldLabel` and `FieldDescription`; `Field`'s `label` prop no longer renders a standalone label.
94
102
 
95
103
  ## Static component
@@ -26,13 +26,40 @@ import { Input } from "@thebase/ui";
26
26
  </div>
27
27
  ```
28
28
 
29
+ ### Addons (`start` / `end` slots)
30
+
31
+ Put text, icons or buttons inside the field with the `start` and `end` slots. The text stays clear of them, and the label moves over for `start`. Content can be plain text, an `Icon`, a `Kbd` or a `Button`. For a textarea, see the `footer` slot on [Textarea](/examples/blocks.html#/docs/components/textarea).
32
+
33
+ ```base-ui
34
+ <div style="max-width: 28rem" class="w-100 pt-3 d-flex flex-column gap-4">
35
+ <Input label="'Website'" placeholder="'example.com'">
36
+ <t t-set-slot="start"><span>https://</span></t>
37
+ </Input>
38
+ <Input label="'Search'">
39
+ <t t-set-slot="end"><Button size="'xs'">Search</Button></t>
40
+ </Input>
41
+ </div>
42
+ ```
43
+
44
+ ### Help tooltip (`useTip`)
45
+
46
+ Set `useTip="1"` to move `supportingText` into a tooltip: a question-mark icon appears right after the label, in the same label box, and the text shows on hover or focus. Error text still shows under the field.
47
+
48
+ ```base-ui
49
+ <div style="max-width: 28rem" class="w-100 pt-3">
50
+ <Input label="'Email'" supportingText="'We only use it to send receipts'" useTip="1" leadingIcon="'mail'"/>
51
+ </div>
52
+ ```
53
+
29
54
  | Prop | Type | Notes |
30
55
  | --- | --- | --- |
31
56
  | `value` | `String` | controlled value; the component never mutates it itself |
32
57
  | `label` | `String` | Material-style outlined field: label rests inside, floats onto the border when focused/filled (or when `placeholder` is set) |
33
58
  | `labelBackground` | `String` | any CSS colour for the floated label's background (default matches the field, `--bu-field-bg`); use it when the field sits on a surface of a different colour |
34
59
  | `supportingText` | `String` | helper line under the field, linked via `aria-describedby` |
60
+ | `useTip` | `Number` | `0` (default) shows `supportingText` under the field; `1` hides it and shows it in a tooltip on a question-mark icon right after the label (error text still shows under the field) |
35
61
  | `errorText` | `String` | marks the field invalid, replaces `supportingText`, swaps the trailing icon for an error icon, sets `aria-invalid` |
62
+ | slots `start` / `end` | slot | content drawn inside the box at the left/right edge (e.g. text, `Icon`, `Kbd`, `Button`); forces the outlined box even without a `label` |
36
63
  | `leadingIcon` / `trailingIcon` | `String` | Lucide icon names (outlined mode only) |
37
64
  | `maxLength` | `Number` | native limit; outlined mode also shows a `n/max` counter |
38
65
  | `placeholder` | `String` | |
@@ -22,12 +22,9 @@ import { Kbd } from "@thebase/ui";
22
22
  Accept <Kbd className="'ms-2'">⏎ Enter</Kbd>
23
23
  </t>
24
24
  </Button>
25
- <InputGroup class="w-100">
26
- <InputGroupInput placeholder="'Search...'"/>
27
- <InputGroupAddon align="'inline-end'">
28
- <Kbd>⌘K</Kbd>
29
- </InputGroupAddon>
30
- </InputGroup>
25
+ <Input label="'Search'" className="'w-100'">
26
+ <t t-set-slot="end"><Kbd>⌘K</Kbd></t>
27
+ </Input>
31
28
  </div>
32
29
  ```
33
30
 
@@ -107,6 +107,8 @@ A fenced ` ```base-ui ` block renders as a live component, not a code sample:
107
107
 
108
108
  See `dist/baseui.registry.json` for the full attribute list.
109
109
 
110
+ Task-list checkboxes (`- [ ] item`) get an `aria-label` with the item text after rendering. On coarse pointers (touch), links in tables and lists and checkboxes get larger touch targets. Tables scroll horizontally inside their own container.
111
+
110
112
  ## Events
111
113
 
112
114
  - `baseui:markdown-render` — fired after Markdown parses and diagrams finish enhancing (`detail.html`).
@@ -30,14 +30,9 @@ import { MessageScroller } from "@thebase/ui";
30
30
  </MessageScroller>
31
31
  </div>
32
32
  <CardFooter className="'border-top p-3'">
33
- <InputGroup className="'w-100'">
34
- <InputGroupTextarea placeholder="'Type your message...'" rows="1"/>
35
- <InputGroupAddon align="'block-end'">
36
- <InputGroupButton>
37
- <Icon name="'arrow-up'"/>
38
- </InputGroupButton>
39
- </InputGroupAddon>
40
- </InputGroup>
33
+ <Textarea placeholder="'Type your message...'" rows="1" className="'w-100'">
34
+ <t t-set-slot="footer"><span/><Button size="'icon-xs'" ariaLabel="'Send'"><Icon name="'arrow-up'"/></Button></t>
35
+ </Textarea>
41
36
  </CardFooter>
42
37
  </Card>
43
38
  </div>
@@ -19,6 +19,19 @@ import { NativeSelect } from "@thebase/ui";
19
19
  </div>
20
20
  ```
21
21
 
22
+ ### Help tooltip (`useTip`)
23
+
24
+ Set `useTip="1"` to move `supportingText` into a tooltip: a question-mark icon appears right after the label, in the same label box, and the text shows on hover or focus. Error text still shows under the field.
25
+
26
+ ```base-ui
27
+ <div style="max-width: 28rem" class="w-100 pt-3">
28
+ <NativeSelect label="'Fruit'" supportingText="'Shown on your order'" useTip="1">
29
+ <option value="'apple'">Apple</option>
30
+ <option value="'banana'">Banana</option>
31
+ </NativeSelect>
32
+ </div>
33
+ ```
34
+
22
35
  | Component | Prop | Type | Notes |
23
36
  | --- | --- | --- | --- |
24
37
  | `NativeSelect` | `value` | `String` | optional |
@@ -28,7 +41,7 @@ import { NativeSelect } from "@thebase/ui";
28
41
  | `NativeSelect` | `ariaLabel` / `aria-label` | `String` | optional, accessible name for the control |
29
42
  | `NativeSelect` | `id` | `String` | optional, e.g. for `Label`'s `for` |
30
43
  | `NativeSelect` | `onChange` | `Function` | optional |
31
- | `NativeSelect` | `label`, `labelBackground`, `supportingText`, `errorText`, `invalid` | `String` / `Boolean` | Material-style outlined field, same behaviour as [Input](/examples/blocks.html#/docs/components/input): the label floats onto the border, `errorText` replaces `supportingText`. Also inherited from a parent `Field`. |
44
+ | `NativeSelect` | `label`, `labelBackground`, `supportingText`, `useTip`, `errorText`, `invalid` | `String` / `Boolean` | Material-style outlined field, same behaviour as [Input](/examples/blocks.html#/docs/components/input): the label floats onto the border, `errorText` replaces `supportingText`. Also inherited from a parent `Field`. |
32
45
 
33
46
  See [Base Components](/examples/blocks.html#/docs/guide/owl-components) for how to load `@base/owl` and `dist/baseui.templates.xml`.
34
47
 
@@ -39,3 +39,5 @@ See [Base Components](/examples/blocks.html#/docs/guide/owl-components) for how
39
39
  ```
40
40
 
41
41
  The Base UI adds `menubar`/`menuitem` roles and Left/Right arrow focus movement.
42
+
43
+ Below 768px the menu does not wrap: it scrolls horizontally with a fade on the right edge and no visible scrollbar, so a sticky header keeps a constant height. Items never shrink or wrap their text.
@@ -19,12 +19,28 @@ import { Select, SelectContent, SelectItem, SelectTrigger } from "@thebase/ui";
19
19
  </div>
20
20
  ```
21
21
 
22
+ ### Help tooltip (`useTip`)
23
+
24
+ Set `useTip="1"` to move `supportingText` into a tooltip: a question-mark icon appears right after the label, in the same label box, and the text shows on hover or focus. Error text still shows under the field.
25
+
26
+ ```base-ui
27
+ <div style="max-width: 28rem" class="w-100 pt-3">
28
+ <Select label="'Theme'" value="'dark'" supportingText="'Applies to this device only'" useTip="1">
29
+ <SelectTrigger>Dark</SelectTrigger>
30
+ <SelectContent>
31
+ <SelectItem value="'light'">Light</SelectItem>
32
+ <SelectItem value="'dark'">Dark</SelectItem>
33
+ </SelectContent>
34
+ </Select>
35
+ </div>
36
+ ```
37
+
22
38
  | Component | Prop | Type | Notes |
23
39
  | --- | --- | --- | --- |
24
40
  | `Select` | `value` | `String` | optional |
25
41
  | `Select` | `onChange` | `Function` | optional |
26
42
  | `Select` | `className` | `String` | optional |
27
- | `Select` | `label`, `labelBackground`, `supportingText`, `errorText`, `invalid` | `String` / `Boolean` | Material-style outlined field, same behaviour as [Input](/examples/blocks.html#/docs/components/input): the label floats onto the border, `errorText` replaces `supportingText`. Also inherited from a parent `Field`. |
43
+ | `Select` | `label`, `labelBackground`, `supportingText`, `useTip`, `errorText`, `invalid` | `String` / `Boolean` | Material-style outlined field, same behaviour as [Input](/examples/blocks.html#/docs/components/input): the label floats onto the border, `errorText` replaces `supportingText`. Also inherited from a parent `Field`. |
28
44
  | `SelectContent` | `className` | `String` | optional |
29
45
  | `SelectItem` | `value` | `String` | required |
30
46
  | `SelectItem` | `className` | `String` | optional |
@@ -45,6 +45,8 @@ import { SidebarClose, SidebarTrigger } from "@thebase/ui";
45
45
 
46
46
  `Shell` wraps the existing `Sidebar` primitive internally to provide the off-canvas/mobile drawer behavior (`open`/`defaultOpen`/`onOpenChange` are forwarded to it) and additionally tracks its own desktop `collapsed` state, exposed to descendants via `env.shell`/`env.setShellCollapsed`. A single `SidebarTrigger` toggles both: it opens/closes the mobile drawer via `env.setSidebarOpen` and, when mounted inside a `Shell`, also toggles the desktop collapse rail via `env.setShellCollapsed` — no separate collapse-trigger component is needed.
47
47
 
48
+ Below 992px (`max-width: 991.98px`) the sidebar becomes the off-canvas drawer, so tablets in portrait get the drawer too; at 992px and above it is the collapsible desktop rail.
49
+
48
50
  Four cross-cutting concerns are opt-in via props instead of baked into the layout:
49
51
 
50
52
  - `authState` — an arbitrary object (e.g. `{ username, onLogout }`), exposed to descendants via `env.shell.authState`. `ShellUserMenu` reads it directly and renders nothing when it's absent; pass its own default slot to fully customize the markup instead of the built-in username/logout row.