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

docs: added custom components initial content #1855

Closed
wants to merge 3 commits into from

Conversation

gentaDemnushaj
Copy link
Contributor

@gentaDemnushaj gentaDemnushaj commented Oct 31, 2024

DRAFT - PLEASE DO NOT CLOSE THIS PR

ATENTION! YOU SHOULD NOW BRANCH FROM PREPROD WHEN YOU UPDATE


Thank you for contributing to the documentation.

Do the changes you have made apply to both Current and Previous versions?

Have you done a trial build to check all new or changed links?

Is there anything else you would like us to know?

This week's exciting advice from the style guide

  • Write your headings in sentence case:

    • A good example
      This is a correct heading.
    • A Bad Example
      This is not a correct heading.

@gentaDemnushaj gentaDemnushaj self-assigned this Oct 31, 2024
@gentaDemnushaj gentaDemnushaj changed the title chore: added custom components initial content docs: added custom components initial content Oct 31, 2024
Copy link
Contributor

@matteematt matteematt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really fantastic, you should be very proud of yourself. Please don't be put off by the amount of comments, this is a very substantial piece of work and therefore will always have generated many points of feedback.

@@ -0,0 +1,75 @@
# Component Lifecycles

Web Components go through several lifecycle stages from creation to removal. Understanding these lifecycles is crucial for proper component initialization, cleanup, and state management.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to be careful and consistant with our terminology here. I think except the the intro in the previous page we should always refer to these as Genesis Elements. Not custom elements or web components.


```

- `ref("buttonElement")`: The ref directive assigns the `<button>` element to the `buttonElement` property on the `<my-button>` component instance.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `ref("buttonElement")`: The ref directive assigns the `<button>` element to the `buttonElement` property on the `<my-button>` component instance.
- `ref("buttonElement")`: The ref directive assigns a reference to the `<button>` element to the `buttonElement` property on the `<my-button>` component instance.

```
- Property Name: The name of the property that will store the DOM reference in the component. The element with ref(propertyName) will be assigned to this property.

## Slotted
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is all really good. It has me wondering if we should introduce the concept of slot in the html earlier on though in addition to this, I am unsure just introducing it here makes it clear what the use case is.

<!-- Look into how to implement this -->

### Usage in HTML

Copy link
Contributor

@matteematt matteematt Nov 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

    template: html<MyButton>`
        <div>
            ${whenElse(
                x => !x.ready,
                html<MyButton>`Loading...`,
                html<MyButton>`<button>Data Loaded: ${x => x.data.message}</button>`
            )}
        </div>
    `,

`,
})
export class MyButtonList extends GenesisElement {
@observable buttons: string[] = ["Click Me", "Submit", "Reset"]; // Static list of button labels
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@observable buttons: string[] = ["Click Me", "Submit", "Reset"]; // Static list of button labels
buttons: string[] = ["Click Me", "Submit", "Reset"]; // Static list of button labels

This doesn't need to be observable for your example, and the way observable works with array is a bit tricky so I wouldn't just use the keyword here without an explanation

- Expression: Specifies the data source for repeat.
- Item Template: Defines the HTML structure for each item.
- Options: Adds control over item positioning and view recycling (optional).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we might want to elaborate on repeat a bit to explain some of the more advanced bits it can do. See here where it talks about opting into positioning. You probably don't need to go as in depth but we should mention it. Also the view recycling section

@matteematt
Copy link
Contributor

matteematt commented Nov 1, 2024

Sync

The sync directive allows for a two-way data binding between the model and view. In all of the previous examples, the binding between the model and the view has only been one way - from the model to the view. Consider this example with a simple checkbox.

@customElement({
  name: 'my-element',
  template: html<MyElement>`
    <rapid-checkbox
      ?checked=${(x) => x.isSelected}
    >Checkbox
    </rapid-checkbox>
    `,
})
export class MyElement extends GenesisElement {
  @observable isSelected = true;
  isSelectedChanged() {
    console.log(this.isSelected);
  }
}

When my-element is added to the DOM, the isSelected property is set to true by default. If you run this example you'll see that the checkbox is checked. However, if you click the checkbox notice that you don't see any console output! That is because the data binding is only flowing one way, and changing the checkbox state isn't being reflected back to the model (isSelected isn't changed).

Now we'll add the use the sync directive.

@customElement({
  name: 'my-element',
  template: html<MyElement>`
    <rapid-checkbox
      ?checked=${sync((x) => x.isSelected, 'boolean')}
    >Checkbox
    </rapid-checkbox>
    `,
})
export class MyElement extends GenesisElement {
  @observable isSelected = true;
  isSelectedChanged() {
    console.log(this.isSelected);
  }
}

The property (and therefore checkbox state) is set as true by default as previously, but if you interact with the checkbox this time you should see that the console logs due to isSelected updating, therefore triggering isSelectedChanged. This is because sync is allowing for the data to flow from the view (checkbox checked attribute) to the model (MyElement isSelected) property.

Usage in HTML

html`
  <rapid-text-area :value=${sync((x) => x.textAreaValue)}><rapid-text-area>
  <rapid-checkbox ?checked=${sync((x) => x.isSelected, 'boolean')}><rapid-checkbox>
  <rapid-number-field :value=${sync((x) => x.numberInputValue, 'number')}><rapid-number-field>
`

The above configuration example shows the subtle differences required when using sync with different components.

  1. A text area has its main state updated via the :value property. As the property and the reflected value are both a string we dont need the second parameter added to the sync directive.
  2. Checkbox uses the checked attribute to hold its state, and as it's a boolean recall we use the ? prefix for the data binding. As we want to reflect it back to a boolean value on the model we need to specify the boolean type in the second parameter to the sync directive`.
  3. The number field is similar to the text field. However it's likely on the model we want numberInputValue to be a number type, so to do the conversion from the string attribute automatically we specifcy the number type as the second parameter to the sync directive

Syntax Breakdown

sync(binding, conversionType, eventName)
  • Binding: the function that defines the binding to the chosen variable on the model.
  • Conversion Type: this optional parameter allows sync to automatically convert the underlying data type from the string on the variable to the correct type on the model.
    • string, this is the default
    • number
    • time
    • boolean
  • Event Name: this optional parameter is used by sync to know what event to listen to from the component to reflect the data back to the model.
    • "input"
    • "change"
    • "default"

@github-actions github-actions bot deleted the gd/custom-component branch November 27, 2024 13:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants