Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lwb-88 Implement inline_text_semantics anchor component #89

Merged
merged 2 commits into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions resources/views/inline_text_semantics/anchor.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<a {!! $globalAttributes !!} {!! $specificAttributes !!}>
{{ $slot }}
</a>
144 changes: 144 additions & 0 deletions src/Components/InlineTextSemantics/Anchor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
<?php

namespace T73biz\LwBits\Components\InlineTextSemantics;

use Illuminate\Contracts\Foundation\Application as ContractedApplication;
use Illuminate\Contracts\View\Factory;
use Illuminate\Contracts\View\View as ContractedView;
use Illuminate\Foundation\Application;
use Illuminate\View\View;
use Livewire\Component;
use Livewire\Features\SupportAttributes\AttributeCollection;
use T73biz\LwBits\Components\GlobalAttributesTrait;

/**
* Class Anchor
*/
class Anchor extends Component
{
use GlobalAttributesTrait;

private AttributeCollection $specificAttributes;

/**
* Causes the browser to treat the linked URL as a download. Can be used with or without a filename value:
*/
public string $download = '';

/**
* The URL that the hyperlink points to. Links are not restricted to HTTP-based URLs — they can use any URL scheme
* supported by browsers:
*/
public string $href = '';

/**
* This attribute indicates the language of the linked resource. It is purely advisory. Allowed values are determined
* by BCP47 for HTML5 and by RFC1766 for HTML 4.01:
*/
public string $hreflang = '';

/**
* A space-separated list of URLs. When the link is followed, the browser will send POST requests with the body PING
* to the URLs. Typically used for tracking.
*/
public string $ping = '';

/**
* How much of the referrer to send when following the link.
*
* no-referrer: The Referer header will not be sent.
* no-referrer-when-downgrade: The Referer header will not be sent to origins without TLS (HTTPS).
* origin: The sent referrer will be limited to the origin of the referring page: its scheme, host, and port.
* origin-when-cross-origin: The referrer sent to other origins will be limited to the scheme, the host, and the
* port. Navigations on the same origin will still include the path.
* same-origin: A referrer will be sent for same origin, but cross-origin requests will contain no referrer information.
* strict-origin: Only send the origin of the document as the referrer when the protocol security level stays the
* same (HTTPS→HTTPS), but don't send it to a less secure destination (HTTPS→HTTP).
* strict-origin-when-cross-origin (default): Send a full URL when performing a same-origin request, only send the
* origin when the protocol security level stays the same (HTTPS→HTTPS), and send no header to a less secure
* destination (HTTPS→HTTP).
* unsafe-url: The referrer will include the origin and the path (but not the fragment, password, or username).
* This value is unsafe, because it leaks origins and paths from TLS-protected resources to insecure origins.
*/
public string $referrerPolicy = '';

/**
* The relationship of the linked URL as space-separated link types.
*/
public string $rel = '';

/**
* Where to display the linked URL, as the name for a browsing context (a tab, window, or <iframe>). The following
* keywords have special meanings for where to load the URL:
*
* _self: The current browsing context. (Default)
* _blank: Usually a new tab, but users can configure browsers to open a new window instead.
* _parent: The parent browsing context of the current one. If no parent, behaves as _self.
* _top: The topmost browsing context. To be specific, this means the "highest" context that's an ancestor of the
* current one. If no ancestors, behaves as _self.
* _unfencedTop: Allows embedded fenced frames to navigate the top-level frame (i.e. traversing beyond the root of
* the fenced frame, unlike other reserved destinations). Note that the navigation will still succeed if this
* is used outside of a fenced frame context, but it will not act like a reserved keyword.
*/
public string $target = '';

/**
* Hints at the linked URL's format with a MIME type. No built-in functionality.
*/
public string $type = '';

/**
* Standard mount function
*/
public function mount(): void
{
$this->setGlobalAttributes();
$this->specificAttributes = new AttributeCollection();
if (! empty($this->download)) {
$this->specificAttributes->add(['download' => $this->download]);
}

if (! empty($this->href)) {
$this->specificAttributes->add(['href' => $this->href]);
}

if (! empty($this->hreflang)) {
$this->specificAttributes->add(['hreflang' => $this->hreflang]);
}

if (! empty($this->ping)) {
$this->specificAttributes->add(['ping' => $this->ping]);
}

if (! empty($this->referrerPolicy)) {
$this->specificAttributes->add(['referrerpolicy' => $this->referrerPolicy]);
}

if (! empty($this->rel)) {
$this->specificAttributes->add(['rel' => $this->rel]);
}

if (! empty($this->target)) {
$this->specificAttributes->add(['target' => $this->target]);
}

if (! empty($this->type)) {
$this->specificAttributes->add(['type' => $this->type]);
}
}

/**
* Standard render function
*/
public function render(): Application|ContractedApplication|ContractedView|Factory|View
{
return view(
'lw-bits::inline_text_semantics.anchor',
[
'globalAttributes' => $this->getGlobalAttributes(),
'specificAttributes' => $this->parseAttributes($this->specificAttributes),
'slot' => '',
]
);
}
}
159 changes: 159 additions & 0 deletions tests/Feature/InlineTextSemantics/AnchorTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
<?php

use Livewire\Livewire;
use T73biz\LwBits\Tests\TestSupport\Components\InlineTextSemantics\MyAnchor;

it('can render', function () {
Livewire::test(MyAnchor::class)
->assertStatus(200);
});

it('can render with accesskey', function () {
Livewire::test(MyAnchor::class, ['accessKey' => true])
->assertSee('accesskey');
});

it('can render with autocapitalize', function () {
Livewire::test(MyAnchor::class, ['autoCapitalize' => true])
->assertSee('autocapitalize');
});

it('can render with autofocus', function () {
Livewire::test(MyAnchor::class, ['autoFocus' => true])
->assertSee('autofocus');
});

it('can render with contenteditable', function () {
Livewire::test(MyAnchor::class, ['contentEditable' => true])
->assertSee('contenteditable');
});

it('can render with css classes', function () {
Livewire::test(MyAnchor::class, ['cssClasses' => ['class1', 'class2']])
->assertSee('class="class1 class2"', false);
});

it('can render with data-*', function () {
Livewire::test(MyAnchor::class, ['data' => ['name' => 'main-anchor']])
->assertSee('data-name="main-anchor"', false);
});

it('can render with dir', function () {
Livewire::test(MyAnchor::class, ['direction' => 'rtl'])
->assertSee('dir="rtl"', false);
});

it('can render with draggable', function () {
Livewire::test(MyAnchor::class, ['draggable' => true])
->assertSee('draggable');
});

it('can render with enterkeyhint', function () {
Livewire::test(MyAnchor::class, ['enterKeyHint' => 'enter'])
->assertSee('enterkeyhint="enter"', false);
});

it('can render with hidden', function () {
Livewire::test(MyAnchor::class, ['hidden' => true])
->assertSee('hidden');
});

it('can render with id', function () {
Livewire::test(MyAnchor::class, ['id' => 'main-anchor'])
->assertSee('id="main-anchor"', false);
});

it('can render with language', function () {
Livewire::test(MyAnchor::class, ['language' => 'en'])
->assertSee('lang="en"', false);
});

it('can render with nonce', function () {
Livewire::test(MyAnchor::class, ['nonce' => 'abc123'])
->assertSee('nonce="abc123"', false);
});

it('can render with parts', function () {
Livewire::test(MyAnchor::class, ['parts' => ['part1', 'part2']])
->assertSee('part="part1 part2"', false);
});

it('can render with popOver', function () {
Livewire::test(MyAnchor::class, ['popOver' => true])
->assertSee('popover');
});

it('can render with role', function () {
Livewire::test(MyAnchor::class, ['role' => 'main'])
->assertSee('role="main"', false);
});

it('can render with slot', function () {
Livewire::test(MyAnchor::class, ['slotAttribute' => 'main-anchor'])
->assertSee('slot="main-anchor"', false);
});

it('can render with spellcheck', function () {
Livewire::test(MyAnchor::class, ['spellCheck' => true])
->assertSee('spellcheck');
});

it('can render with styles', function () {
Livewire::test(MyAnchor::class, ['styles' => ['color' => 'red', 'font-size' => '16px']])
->assertSee('style="color:red;font-size:16px"', false);
});

it('can render with tabindex', function () {
Livewire::test(MyAnchor::class, ['tabIndex' => 1])
->assertSee('tabindex="1"', false);
});

it('can render with title', function () {
Livewire::test(MyAnchor::class, ['title' => 'main-anchor'])
->assertSee('title="main-anchor"', false);
});

it('can render with translate', function () {
Livewire::test(MyAnchor::class, ['translate' => true])
->assertSee('translate');
});

it('can render with download', function () {
Livewire::test(MyAnchor::class, ['download' => 'main-anchor'])
->assertSee('download="main-anchor"', false);
});

it('can render with href', function () {
Livewire::test(MyAnchor::class, ['href' => 'https://example.com'])
->assertSee('href="https://example.com"', false);
});

it('can render with hreflang', function () {
Livewire::test(MyAnchor::class, ['hreflang' => 'en'])
->assertSee('hreflang="en"', false);
});

it('can render with ping', function () {
Livewire::test(MyAnchor::class, ['ping' => 'https://example.com'])
->assertSee('ping="https://example.com"', false);
});

it('can render with referrerPolicy', function () {
Livewire::test(MyAnchor::class, ['referrerPolicy' => 'no-referrer'])
->assertSee('referrerpolicy="no-referrer"', false);
});

it('can render with rel', function () {
Livewire::test(MyAnchor::class, ['rel' => 'noopener'])
->assertSee('rel="noopener"', false);
});

it('can render with target', function () {
Livewire::test(MyAnchor::class, ['target' => '_blank'])
->assertSee('target="_blank"', false);
});

it('can render with type', function () {
Livewire::test(MyAnchor::class, ['type' => 'text/html'])
->assertSee('type="text/html"', false);
});
9 changes: 9 additions & 0 deletions tests/TestSupport/Components/InlineTextSemantics/MyAnchor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace T73biz\LwBits\Tests\TestSupport\Components\InlineTextSemantics;

use T73biz\LwBits\Components\InlineTextSemantics\Anchor;

class MyAnchor extends Anchor
{
}