diff --git a/book.toml b/book.toml
index e5be345..7d2b9c4 100644
--- a/book.toml
+++ b/book.toml
@@ -6,6 +6,7 @@ src = "src"
title = "Breez SDK"
[output.html]
+additional-js = ["tabs.js"]
git-repository-url = "https://github.com/breez/breez-sdk-docs"
edit-url-template = "https://github.com/breez/breez-sdk-docs/edit/main/{path}"
diff --git a/src/guide/getting_started.md b/src/guide/getting_started.md
index 9e0b572..322612a 100644
--- a/src/guide/getting_started.md
+++ b/src/guide/getting_started.md
@@ -15,6 +15,11 @@ Connecting to a node requires a seed (your master key) and credentials. The seed
Breez SDK is available in several platforms. Follow the [Installing](install.md) page for instructions on how to install on your platform.
+
+Rust
+
+
+The first step is to register a new node. In order to do that a seed is needed.
## Registering a new node
```rust,no_run
let seed = ;
@@ -62,4 +67,138 @@ if let Some(node_state) = sdk.node_info()? {
let balance_onchain = node_state.onchain_balance_msat;
}
```
+
+Swift
+
+
+The first step is to register a new node
+## Registering a new node
+```swift
+do {
+ let seed = try mnemonicToSeed(phrase: "")
+ let inviteCode = ""
+
+ // register_node takes either greenlight credentials (certifate & key) or invite code.
+ // At this example we are using the invite code option.
+ let credentials = try registerNode(network: Network.bitcoin, seed: seed, registerCredentials: nil, inviteCode: inviteCode)
+} catch {
+ // handle error
+}
+```
+
+## Recovering an existing node
+```swift
+do {
+ let seed = try mnemonicToSeed(phrase: "")
+ let credentials = try recoverNode(network: Network.bitcoin, seed: seed)
+} catch {
+ // handle error
+}
+```
+
+Once the credentials are retrieved they should be saved in a secured storage.
+The next step is to initialize the SDK and start the node:
+
+## Initializing the SDK
+```swift
+
+// SDK events listener
+class SDKListener: EventListener {
+ func onEvent(e: BreezEvent) {
+ print("received event ", e)
+ }
+}
+
+// Create the default config
+var config = defaultConfig(envType: EnvironmentType.production)
+
+// Customize the config object according to your needs
+config.apiKey = "your API key";
+config.workingDir = "path to an existing directory";
+
+do {
+ let sdk = try initServices(config: config, seed: seed, creds: credentials, listener: SDKListener());
+ try sdk.start();
+} catch{
+ // handle error
+}
+```
+
+At any point we can fetch our balance from the Greenlight node:
+
+```swift
+do {
+ let nodeInfo = try sdk.nodeInfo()
+ let lnBalance = nodeInfo?.channelsBalanceMsat
+ let onchainBalance = nodeInfo?.onchainBalanceMsat
+} catch {
+ // handle error
+}
+```
+
+
+React Native
+
+
+The first step is to register a new node
+## Registering a new node
+```typescript
+try {
+ const seed = await mnemonicToSeed("");
+ const invite_code = "";
+
+ // register_node takes either greenlight credentials (certifate & key) or invite code.
+ // At this example we are using the invite code option.
+ const credentials = await registerNode(Network.BITCOIN, seed, inviteCode);
+} catch (error) {
+ console.log(error)
+}
+```
+
+## Recovering an existing node
+```typescript
+ const seed = await mnemonicToSeed("");
+ const credentials = await recoverNode(Network.BITCOIN, seed);
+```
+
+Once the credentials are retrieved they should be saved in a secured storage.
+The next step is to initialize the SDK and start the node:
+
+## Initializing the SDK
+```typescript
+
+// SDK events listener
+addEventListener((type, data) => {
+ console.log(`received event ${type}`);
+})
+
+// Create the default config
+let config = defaultConfig(EnvironmentType.PRODUCTION)
+
+// Customize the config object according to your needs
+config.apiKey = "your API key";
+config.workingDir = "path to an existing directory";
+
+try {
+ const sdkServices = await initServices(config, credentials.deviceKey, credentials.deviceCert, seed);
+ await start();
+} catch (error) {
+ console.log(error);
+}
+```
+
+At any point we can fetch our balance from the Greenlight node:
+
+```typescript
+try {
+ const nodeInfo = await nodeInfo();
+ const lnBalance = nodeInfo.channelsBalanceMsat;
+ const onchainBalance = nodeInfo.onchainBalanceMsat;
+} catch (error) {
+ console.log(error);
+}
+```
+
+
+
You are now ready to receive a Lightning [payment](payments.md).
diff --git a/src/guide/lnurl_auth.md b/src/guide/lnurl_auth.md
index 0a7ea4a..807ca30 100644
--- a/src/guide/lnurl_auth.md
+++ b/src/guide/lnurl_auth.md
@@ -1,6 +1,9 @@
# LNURL-Auth
## Usage
+
+Rust
+
```rust,no_run
// Endpoint can also be of the form:
@@ -21,7 +24,57 @@ if let Ok(LnUrlAuth{data: ad}) = parse(lnurl_auth_url).await {
}
}
```
+
+Swift
+
+```swift
+// Endpoint can also be of the form:
+// keyauth://domain.com/auth?key=val
+let lnurlAuthUrl = "lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttvdankjm3lw3skw0tvdankjm3xdvcn6vtp8q6n2dfsx5mrjwtrxdjnqvtzv56rzcnyv3jrxv3sxqmkyenrvv6kve3exv6nqdtyv43nqcmzvdsnvdrzx33rsenxx5unqc3cxgeqgntfgu"
+
+do {
+ let inputType = try parseInput(s: lnurlAuthUrl)
+ if case .lnUrlAuth(let data) = inputType {
+ let result = try sdk.lnurlAuth(reqData: data)
+ switch result {
+ case .ok:
+ print("Successfully authenticated")
+ case .errorStatus(let data):
+ print("Failed to authenticate")
+ }
+ }
+} catch {
+ // handle error
+}
+```
+
+
+React Native
+
+
+```typescript
+// Endpoint can also be of the form:
+// keyauth://domain.com/auth?key=val
+let lnurlAuthUrl = "lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttvdankjm3lw3skw0tvdankjm3xdvcn6vtp8q6n2dfsx5mrjwtrxdjnqvtzv56rzcnyv3jrxv3sxqmkyenrvv6kve3exv6nqdtyv43nqcmzvdsnvdrzx33rsenxx5unqc3cxgeqgntfgu";
+
+try {
+ const input = await parseInput(lnurlAuthUrl)
+ if (input.type === InputType.LNURL_AUTH) {
+ const result = await lnurlAuth(input.data)
+ if (result.status === "ok") {
+ print("Successfully authenticated")
+ } else {
+ print("Failed to authenticate")
+ }
+ }
+} catch (error) {
+ console.log(error)
+}
+```
+
+
+
## Supported Specs
diff --git a/src/guide/lnurl_pay.md b/src/guide/lnurl_pay.md
index 1019d92..85b088b 100644
--- a/src/guide/lnurl_pay.md
+++ b/src/guide/lnurl_pay.md
@@ -2,6 +2,10 @@
## Usage
+
+Rust
+
+
```rust,no_run
// Endpoint can also be of the form:
// lnurlp://domain.com/lnurl-pay?key=val
@@ -17,6 +21,47 @@ if let Ok(LnUrlPay{data: pd}) = parse(lnurl_pay_url).await {
}
```
+
+Swift
+
+
+```swift
+// Endpoint can also be of the form:
+// lnurlp://domain.com/lnurl-pay?key=val
+// lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttsv9un7um9wdekjmmw84jxywf5x43rvv35xgmr2enrxanr2cfcvsmnwe3jxcukvde48qukgdec89snwde3vfjxvepjxpjnjvtpxd3kvdnxx5crxwpjvyunsephsz36jf
+let lnurlPayUrl = "lightning@address.com";
+do {
+ let inputType = try parseInput(s: lnurlPayUrl)
+ if case .lnUrlPay(let data) = inputType {
+ let amountSats = data.minSendable;
+ try sdk.payLnurl(reqData: data, amountSats: amountSats, comment: "comment")
+ }
+} catch {
+ // handle error
+}
+```
+
+React Native
+
+
+```typescript
+// Endpoint can also be of the form:
+// lnurlp://domain.com/lnurl-pay?key=val
+// lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttsv9un7um9wdekjmmw84jxywf5x43rvv35xgmr2enrxanr2cfcvsmnwe3jxcukvde48qukgdec89snwde3vfjxvepjxpjnjvtpxd3kvdnxx5crxwpjvyunsephsz36jf
+let lnurlPayUrl = "lightning@address.com";
+
+try {
+ const input = await parseInput(lnurlAuthUrl)
+ if (input.type === InputType.LNURL_PAY) {
+ const amountSats = input.minSendable;
+ const result = await payLnurl(input.data, amountSats, "comment")
+ }
+} catch (error) {
+ console.log(error)
+}
+```
+
+
## Supported Specs
diff --git a/src/guide/lnurl_withdraw.md b/src/guide/lnurl_withdraw.md
index 869e833..aaff69b 100644
--- a/src/guide/lnurl_withdraw.md
+++ b/src/guide/lnurl_withdraw.md
@@ -3,6 +3,10 @@
## Usage
+
+Rust
+
+
```rust,no_run
// Endpoint can also be of the form:
// lnurlw://domain.com/lnurl-withdraw?key=val
@@ -16,7 +20,48 @@ if let Ok(LnUrlWithdraw{data: wd}) = parse(lnurl_withdraw_url).await {
sdk.lnurl_withdraw(wd, amount_msat, Some(description)).await?;
}
```
+
+Swift
+
+```swift
+// Endpoint can also be of the form:
+// lnurlw://domain.com/lnurl-withdraw?key=val
+let lnurlWithdrawUrl = "lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4exctthd96xserjv9mn7um9wdekjmmw843xxwpexdnxzen9vgunsvfexq6rvdecx93rgdmyxcuxverrvcursenpxvukzv3c8qunsdecx33nzwpnvg6ryc3hv93nzvecxgcxgwp3h33lxk"
+
+do {
+ let inputType = try parseInput(s: lnurlWithdrawUrl)
+ if case .lnUrlWithdraw(let data) = inputType {
+ let amountSat = data.minWithdrawable
+ let description = "Test withdraw"
+ try sdk.withdrawLnurl(reqData: data, amountSats: amountSat, description: "comment")
+ }
+} catch {
+ // handle error
+}
+
+```
+
+React Native
+
+
+```typescript
+// Endpoint can also be of the form:
+// lnurlw://domain.com/lnurl-withdraw?key=val
+let lnurlWithdrawUrl = "lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4exctthd96xserjv9mn7um9wdekjmmw843xxwpexdnxzen9vgunsvfexq6rvdecx93rgdmyxcuxverrvcursenpxvukzv3c8qunsdecx33nzwpnvg6ryc3hv93nzvecxgcxgwp3h33lxk";
+
+try {
+ const input = await parseInput(lnurlAuthUrl)
+ if (input.type === InputType.LNURL_WITHDRAW) {
+ const amountSats = input.minWithdrawable;
+ const result = await withdrawLnurl(input.data, amountSats, "comment")
+ }
+} catch (error) {
+ console.log(error)
+}
+```
+
+
## Supported Specs
diff --git a/src/guide/payments.md b/src/guide/payments.md
index 96faf60..70aacd5 100644
--- a/src/guide/payments.md
+++ b/src/guide/payments.md
@@ -1,5 +1,8 @@
# Sending and receiving Lightning payments
+
+Rust
+
## Receiving Lightning Payments
Breez SDK doesn't require you to open a channel and set up your inbound liquidity.
Breez SDK automatically connects your node to the LSP peer and you can now receive payments:
@@ -20,3 +23,73 @@ let node_id = "...";
sdk.send_payment(node_id.into(), Some(3000)).await?;
```
+
+Swift
+
+## Receiving Lightning Payments
+Breez SDK doesn't require you to open a channel and set up your inbound liquidity.
+Breez SDK automatically connects your node to the LSP peer and you can now receive payments:
+
+```swift
+do {
+ let invoice = try sdk.receivePayment(amountSats: 3000, description: "Invoice for 3000 sats")
+} catch {
+ // handle error
+}
+```
+
+## Sending Lightning Payments
+```swift
+let bolt11 = "...";
+do {
+ let payment = try sdk.sendPayment(bolt11: bolt11, amountSats: 3000)
+} catch {
+ // handle error
+}
+```
+
+## Sending Spontaneous Lightning Payments
+```swift
+let nodeId = "...";
+do {
+ let payment = try sdk.sendSpontaneousPayment(nodeId: nodeId, amountSats: 3000)
+} catch {
+ // handle error
+}
+```
+
+React Native
+
+## Receiving Lightning Payments
+Breez SDK doesn't require you to open a channel and set up your inbound liquidity.
+Breez SDK automatically connects your node to the LSP peer and you can now receive payments:
+
+```typescript
+try {
+ const invoice = await receivePayment(3000, "Invoice for 3000 sats")
+} catch (error) {
+ console.log(error)
+}
+```
+
+## Sending Lightning Payments
+```typescript
+const bolt11 = "...";
+try {
+ const payment = await sendPayment(bolt11, 3000)
+} catch (error) {
+ console.log(error)
+}
+```
+
+## Sending Spontaneous Lightning Payments
+```typescript
+const nodeId = "...";
+try {
+ const payment = await sendSpontaneousPayment(nodeId, 3000)
+} catch (error) {
+ console.log(error)
+}
+```
+
+
\ No newline at end of file
diff --git a/src/guide/recieve_onchain.md b/src/guide/recieve_onchain.md
index 7c9fb04..c0569eb 100644
--- a/src/guide/recieve_onchain.md
+++ b/src/guide/recieve_onchain.md
@@ -1,10 +1,14 @@
# Receiving an on-chain transaction (swap-in)
There are cases when you have funds in some bitcoin address and you would like to send those to your lightning node.
+
+Rust
+
+
```rust,no_run
let swap_info = sdk.receive_onchain().await?;
-// Send your funds to the bellow bitcoin address
+// Send your funds to the below bitcoin address
let address = swap_info.bitcoin_address;
```
@@ -29,6 +33,114 @@ Once you have a refundable swap in hand, use the follwing code to execute a refu
```rust,no_run
let destination_address = "...".into()
-let sat_per_byte =
-sdk.refund(refundable.bitcoin_address, destination_address, sat_per_byte).await?
+let sat_per_vbyte =
+sdk.refund(refundable.bitcoin_address, destination_address, sat_per_vbyte).await?
```
+
+Swift
+
+
+```swift
+do {
+ let swapInfo = try sdk.receiveOnchain()
+
+ // Send your funds to the bellow bitcoin address
+ let address = swapInfo.bitcoinAddress;
+} catch {
+ // handle error
+}
+```
+
+Once you've sent the funds to the above address, the SDK will monitor this address for unspent confirmed outputs and use a trustless submarine swap to receive these into your Lightning node. You can always monitor the status of the current in-progress swap using the following code:
+
+```swift
+do {
+ let swapInfo = try sdk.inProgressSwap()
+} catch {
+ // handle error
+}
+```
+
+The process of receiving funds via an on-chain address is trustless and uses a submarine swap. This means there are two ways to spend the sent funds:
+
+1. Either by a preimage that is exposed when the Lightning payment is completed - this is the positive case where the swap was successful.
+2. Or by your node when the swap didn't complete within a certain timeout - this is the negative case where your node will execute a refund.
+
+In order to execute a refund, you need to supply an on-chain address to where the refunded amount will be sent. The following code will retrieve the refundable swaps:
+
+```swift
+do {
+ let refundables = try sdk.listRefundables()
+} catch {
+ // handle error
+}
+```
+
+Once you have a refundable swap in hand, use the follwing code to execute a refund:
+
+```swift
+let destinationAddress = "..."
+let satPerVbyte =
+
+do {
+ try sdk.refund(
+ swapAddress: "",
+ toAddress: destinationAddress,
+ satPerVbyte: satPerVbyte)
+} catch {
+ // handle error
+}
+```
+
+React Native
+
+
+```typescript
+try {
+ const swapInfo = await receiveOnchain();
+
+ // Send your funds to the below bitcoin address
+ const address = swapInfo.bitcoinAddress;
+} catch (error) {
+ console.log(error)
+}
+```
+
+Once you've sent the funds to the above address, the SDK will monitor this address for unspent confirmed outputs and use a trustless submarine swap to receive these into your Lightning node. You can always monitor the status of the current in-progress swap using the following code:
+
+```typescript
+try {
+ const swapInfo = await inProgressSwap()
+} catch (error) {
+ console.log(error)
+}
+```
+
+The process of receiving funds via an on-chain address is trustless and uses a submarine swap. This means there are two ways to spend the sent funds:
+
+1. Either by a preimage that is exposed when the Lightning payment is completed - this is the positive case where the swap was successful.
+2. Or by your node when the swap didn't complete within a certain timeout - this is the negative case where your node will execute a refund.
+
+In order to execute a refund, you need to supply an on-chain address to where the refunded amount will be sent. The following code will retrieve the refundable swaps:
+
+```typescript
+try {
+ const refundables = await listRefundables()
+} catch (error) {
+ console.log(error)
+}
+```
+
+Once you have a refundable swap in hand, use the follwing code to execute a refund:
+
+```typescript
+const destinationAddress = "..."
+const satPerVbyte =
+try {
+ const result = await refund(refundable.bitcoinAddress, destinationAddress, satPerVbyte)
+} catch (error) {
+ console.log(error)
+}
+```
+
+
\ No newline at end of file
diff --git a/src/guide/send_onchain.md b/src/guide/send_onchain.md
index 340cd03..12367ee 100644
--- a/src/guide/send_onchain.md
+++ b/src/guide/send_onchain.md
@@ -4,6 +4,10 @@ You can send funds from the Breez SDK wallet to an on-chain address as follows.
First, fetch the current reverse swap fees:
+
+Rust
+
+
```rust,no_run
let current_fees = sdk.fetch_reverse_swap_fees().await?;
@@ -43,7 +47,115 @@ for rs in sdk.in_progress_reverse_swaps().await? {
info!("Reverse swap {} in progress, status is {}", rs.id, rs.breez_status);
}
```
+
+Swift
+
+```swift
+try {
+ let currentFees = try sdk.fetchReverseSwapFees()
+
+ println("Percentage fee for the reverse swap service: \(currentFees.feesPercentage)")
+ println("Estimated miner fees in sats for locking up funds: \(currentFees.feesLockup)")
+ println("Estimated miner fees in sats for claiming funds: \(currentFees.feesClaim)")
+} catch {
+ // handle error
+}
+```
+
+The reverse swap will involve two on-chain transactions, for which the mining fees can only be estimated. They will happen
+automatically once the process is started, but the last two values above are these estimates to help you get a picture
+of the total costs.
+
+Fetching the fees also tells you what is the range of amounts you can send:
+
+```swift
+println("Minimum amount, in sats: \(current_fees.min)")
+println("Maximum amount, in sats: \(current_fees.max)")
+```
+
+Once you checked the fees are acceptable, you can start the reverse swap:
+
+```swift
+let destinationAddress = "bc1.."
+let amountSat = currentFees.min
+let satPerVbyte =
+try {
+ try sdk.sendOnchain(amountSat: amountSat, onchainRecipientAddress: destinationAddress, pairHash: currentFees.feesHash, satPerVbyte: satPerVbyte)
+} catch {
+ // handle error
+}
+```
+
+Starting the reverse swap will trigger a HODL invoice payment, which will only be settled if the entire swap completes.
+This means you will see an outgoing pending payment in your list of payments, which locks those funds until the invoice
+is either settled or cancelled. This will happen automatically at the end of the reverse swap.
+
+You can check its status with:
+
+```swift
+for rs in sdk.inProgressReverseSwaps() {
+ println("Reverse swap \(rs.id) in progress, status is \(rs.breezStatus)")
+}
+```
+
+React Native
+
+
+```typescript
+try {
+ const currentFees = await fetchReverseSwapFees()
+
+ console.log(`Percentage fee for the reverse swap service: ${currentFees.feesPercentage}`);
+ console.log(`Estimated miner fees in sats for locking up funds: ${currentFees.feesLockup}`);
+ console.log(`Estimated miner fees in sats for claiming funds: ${currentFees.feesClaim}`);
+} catch (error) {
+ console.log(error)
+}
+```
+
+The reverse swap will involve two on-chain transactions, for which the mining fees can only be estimated. They will happen
+automatically once the process is started, but the last two values above are these estimates to help you get a picture
+of the total costs.
+
+Fetching the fees also tells you what is the range of amounts you can send:
+
+```typescript
+console.log(`Minimum amount, in sats: ${current_fees.min}`);
+console.log(`Maximum amount, in sats: ${current_fees.max}`);
+```
+
+Once you checked the fees are acceptable, you can start the reverse swap:
+
+```typescript
+const destinationAddress = "bc1..";
+const amountSat = currentFees.min;
+const satPerVbyte =
+try {
+ const reverseSwapInfo = sendOnchain(amountSat, destinationAddress, currentFees.feesHash, satPerVbyte)
+} catch (error) {
+ console.log(error)
+}
+```
+
+Starting the reverse swap will trigger a HODL invoice payment, which will only be settled if the entire swap completes.
+This means you will see an outgoing pending payment in your list of payments, which locks those funds until the invoice
+is either settled or cancelled. This will happen automatically at the end of the reverse swap.
+
+You can check its status with:
+
+```typescript
+try {
+ const swaps = await inProgressReverseSwaps()
+ for (const swap in swaps) {
+ println(`Reverse swap ${swap.id} in progress, status is ${swap.breezStatus}`);
+ }
+} catch (error) {
+ console.log(error)
+}
+```
+
+
If the reverse swap is successful, you'll get the on-chain payment on your destination address and the HODL invoice will
change from pending to settled.
diff --git a/tabs.js b/tabs.js
new file mode 100644
index 0000000..a804acf
--- /dev/null
+++ b/tabs.js
@@ -0,0 +1,147 @@
+(function () {
+ 'use strict';
+
+ let selected_ = null;
+
+ customElements.define('custom-tabs', class extends HTMLElement {
+
+ constructor() {
+ super(); // always call super() first in the ctor.
+
+ // Create shadow DOM for the component.
+ let shadowRoot = this.attachShadow({ mode: 'open' });
+ shadowRoot.innerHTML = `
+
+
+
+
+
+
+
+ `;
+ }
+
+ get selected() {
+ return selected_;
+ }
+
+ set selected(idx) {
+ selected_ = idx;
+ this._selectTab(idx);
+ this.setAttribute('selected', idx);
+ }
+
+ connectedCallback() {
+ this.setAttribute('role', 'tablist');
+
+ const tabsSlot = this.shadowRoot.querySelector('#tabsSlot');
+ const panelsSlot = this.shadowRoot.querySelector('#panelsSlot');
+
+ this.tabs = tabsSlot.assignedNodes({ flatten: true });
+ this.panels = panelsSlot.assignedNodes({ flatten: true }).filter(el => {
+ return el.nodeType === Node.ELEMENT_NODE;
+ });
+
+ // Save refer to we can remove listeners later.
+ this._boundOnTitleClick = this._onTitleClick.bind(this);
+
+ tabsSlot.addEventListener('click', this._boundOnTitleClick);
+
+ this.selected = this._findFirstSelectedTab() || this._findStoredSelectedTab() || 0;
+ }
+
+ disconnectedCallback() {
+ const tabsSlot = this.shadowRoot.querySelector('#tabsSlot');
+ tabsSlot.removeEventListener('click', this._boundOnTitleClick);
+ }
+
+ _onTitleClick(e) {
+ if (e.target.slot === 'title') {
+ this.selected = this.tabs.indexOf(e.target);
+ e.target.focus();
+ }
+ }
+
+ _findFirstSelectedTab() {
+ let selectedIdx;
+ for (let [i, tab] of this.tabs.entries()) {
+ tab.setAttribute('role', 'tab');
+ if (tab.hasAttribute('selected')) {
+ selectedIdx = i;
+ }
+ }
+ return selectedIdx;
+ }
+
+ _findStoredSelectedTab() {
+ let selectedIdx;
+ if (this.getAttribute("category")) {
+ let selectedText;
+ try { selectedText = localStorage.getItem('mdbook-tabs-' + this.getAttribute("category")); } catch (e) { }
+ if (selectedText) {
+ for (let [i, tab] of this.tabs.entries()) {
+ if (tab.textContent === selectedText) {
+ selectedIdx = i;
+ break;
+ }
+ }
+ }
+ }
+ return selectedIdx;
+ }
+
+ _selectTab(idx = null) {
+ for (let i = 0, tab; tab = this.tabs[i]; ++i) {
+ let select = i === idx;
+ tab.setAttribute('tabindex', select ? 0 : -1);
+ tab.setAttribute('aria-selected', select);
+ this.panels[i].setAttribute('aria-hidden', !select);
+ if (select && this.getAttribute("category") && tab.textContent) {
+ try { localStorage.setItem('mdbook-tabs-' + this.getAttribute("category"), tab.textContent); } catch (e) { }
+ }
+ }
+ }
+
+ });
+
+})();
\ No newline at end of file